Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add meta.docs for each rule #246

Merged
merged 16 commits into from Jul 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 14 additions & 36 deletions src/index.ts
Expand Up @@ -17,50 +17,28 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as fs from 'fs';
import * as path from 'path';
import { TSESLint } from '@typescript-eslint/experimental-utils';

const sonarjsRules: [string, TSESLint.Linter.RuleLevel][] = [
['cognitive-complexity', 'error'],
['elseif-without-else', 'off'],
['generator-without-yield', 'error'],
['max-switch-cases', 'error'],
['no-all-duplicated-branches', 'error'],
['no-collapsible-if', 'error'],
['no-collection-size-mischeck', 'error'],
['no-duplicate-string', 'error'],
['no-duplicated-branches', 'error'],
['no-element-overwrite', 'error'],
['no-empty-collection', 'error'],
['no-extra-arguments', 'error'],
['no-gratuitous-expressions', 'error'],
['no-identical-conditions', 'error'],
['no-identical-functions', 'error'],
['no-identical-expressions', 'error'],
['no-inverted-boolean-check', 'error'],
['no-nested-switch', 'error'],
['no-nested-template-literals', 'error'],
['no-one-iteration-loop', 'error'],
['no-redundant-boolean', 'error'],
['no-redundant-jump', 'error'],
['no-same-line-conditional', 'error'],
['no-small-switch', 'error'],
['no-unused-collection', 'error'],
['no-use-of-empty-return-value', 'error'],
['no-useless-catch', 'error'],
['non-existent-operator', 'error'],
['prefer-immediate-return', 'error'],
['prefer-object-literal', 'error'],
['prefer-single-boolean-return', 'error'],
['prefer-while', 'error'],
];
const sonarjsRules: string[] = fs
.readdirSync(path.join(__dirname, 'rules'))
.map(filename => filename.substr(0, filename.lastIndexOf('.ts')));

const sonarjsRuleModules: { [key: string]: any } = {};

const configs: { recommended: TSESLint.Linter.Config & { plugins: string[] } } = {
recommended: { plugins: ['sonarjs'], rules: {} },
};

sonarjsRules.forEach(rule => (sonarjsRuleModules[rule[0]] = require(`./rules/${rule[0]}`)));
sonarjsRules.forEach(rule => (configs.recommended.rules![`sonarjs/${rule[0]}`] = rule[1]));
sonarjsRules.forEach(rule => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this forEach has a full body now, we probably can merge it with the previous one

sonarjsRuleModules[rule] = require(`./rules/${rule}`);
const {
meta: {
docs: { recommended },
},
} = sonarjsRuleModules[rule];
configs.recommended.rules![`sonarjs/${rule}`] = recommended === false ? 'off' : recommended;
});

export { sonarjsRuleModules as rules, configs };
7 changes: 7 additions & 0 deletions src/rules/cognitive-complexity.ts
Expand Up @@ -30,6 +30,7 @@ import {
issueLocation,
} from '../utils/locations';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

const DEFAULT_THRESHOLD = 15;

Expand All @@ -47,6 +48,12 @@ type Options = [number, 'metric'];
const rule: Rule.RuleModule<string, Options> = {
meta: {
type: 'suggestion',
docs: {
description: 'Cognitive Complexity of functions should not be too high',
category: 'Best Practices',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{ type: 'integer', minimum: 0 },
{
Expand Down
7 changes: 7 additions & 0 deletions src/rules/elseif-without-else.ts
Expand Up @@ -20,10 +20,17 @@

import { TSESTree } from '@typescript-eslint/experimental-utils';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

const rule: Rule.RuleModule = {
meta: {
type: 'suggestion',
docs: {
description: '"if ... else if" constructs should end with "else" clauses',
category: 'Best Practices',
recommended: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be off to be consistent with index.ts?
Can we rely on this value from docs when creating profile in index.ts? So that it's not duplicated

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be off to be consistent with index.ts?

No, it shouldn't unfortunately. Here is the type of the recommended property.

Can we rely on this value from docs when creating profile in index.ts? So that it's not duplicated

Yes, we can. I will do that.

url: docsUrl(__filename),
},
},
create(context: Rule.RuleContext) {
return {
Expand Down
7 changes: 7 additions & 0 deletions src/rules/generator-without-yield.ts
Expand Up @@ -21,12 +21,19 @@
import { TSESTree } from '@typescript-eslint/experimental-utils';
import { getMainFunctionTokenLocation } from '../utils/locations';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

const MESSAGE = 'Add a "yield" statement to this generator.';

const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'Generators should "yield" something',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
},
create(context: Rule.RuleContext) {
const yieldStack: number[] = [];
Expand Down
7 changes: 7 additions & 0 deletions src/rules/max-switch-cases.ts
Expand Up @@ -21,6 +21,7 @@

import { TSESTree } from '@typescript-eslint/experimental-utils';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

const MESSAGE =
'Reduce the number of non-empty switch cases from {{numSwitchCases}} to at most {{maxSwitchCases}}.';
Expand All @@ -33,6 +34,12 @@ type Options = [number];
const rule: Rule.RuleModule<string, Options> = {
meta: {
type: 'suggestion',
docs: {
description: '"switch" statements should not have too many "case" clauses',
category: 'Best Practices',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
type: 'integer',
Expand Down
8 changes: 8 additions & 0 deletions src/rules/no-all-duplicated-branches.ts
Expand Up @@ -24,6 +24,7 @@ import { Rule } from '../utils/types';
import { isIfStatement } from '../utils/nodes';
import { areEquivalent } from '../utils/equivalence';
import { collectIfBranches, collectSwitchBranches } from '../utils/conditions';
import docsUrl from '../utils/docs-url';

const MESSAGE =
"Remove this conditional structure or edit its code blocks so that they're not all the same.";
Expand All @@ -33,6 +34,13 @@ const MESSAGE_CONDITIONAL_EXPRESSION =
const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description:
'All branches in a conditional structure should not have exactly the same implementation',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
},
create(context: Rule.RuleContext) {
return {
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-collapsible-if.ts
Expand Up @@ -23,10 +23,17 @@ import { TSESTree } from '@typescript-eslint/experimental-utils';
import { Rule } from '../utils/types';
import { isIfStatement, isBlockStatement } from '../utils/nodes';
import { report, issueLocation } from '../utils/locations';
import docsUrl from '../utils/docs-url';

const rule: Rule.RuleModule = {
meta: {
type: 'suggestion',
docs: {
description: 'Collapsible "if" statements should be merged',
category: 'Best Practices',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
// internal parameter
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-collection-size-mischeck.ts
Expand Up @@ -22,13 +22,20 @@
import { TSESTree } from '@typescript-eslint/experimental-utils';
import { Rule } from '../utils/types';
import { isRequiredParserServices, RequiredParserServices } from '../utils/parser-services';
import docsUrl from '../utils/docs-url';

const CollectionLike = ['Array', 'Map', 'Set', 'WeakMap', 'WeakSet'];
const CollectionSizeLike = ['length', 'size'];

const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'Collection sizes and array length comparisons should make sense',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
},
create(context: Rule.RuleContext) {
const services = context.parserServices;
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-duplicate-string.ts
Expand Up @@ -21,6 +21,7 @@

import { TSESTree } from '@typescript-eslint/experimental-utils';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

// Number of times a literal must be duplicated to trigger an issue
const DEFAULT_THRESHOLD = 3;
Expand All @@ -39,6 +40,12 @@ type Options = [number];
const rule: Rule.RuleModule<string, Options> = {
meta: {
type: 'suggestion',
docs: {
description: 'String literals should not be duplicated',
category: 'Best Practices',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [{ type: 'integer', minimum: 2 }],
},

Expand Down
8 changes: 8 additions & 0 deletions src/rules/no-duplicated-branches.ts
Expand Up @@ -25,13 +25,21 @@ import { isIfStatement, isBlockStatement } from '../utils/nodes';
import { areEquivalent } from '../utils/equivalence';
import { collectIfBranches, takeWithoutBreak, collectSwitchBranches } from '../utils/conditions';
import { report, issueLocation } from '../utils/locations';
import docsUrl from '../utils/docs-url';

const MESSAGE =
"This {{type}}'s code block is the same as the block for the {{type}} on line {{line}}.";

const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description:
'Two branches in a conditional structure should not have exactly the same implementation',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
// internal parameter
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-element-overwrite.ts
Expand Up @@ -31,13 +31,20 @@ import {
} from '../utils/nodes';
import { report, issueLocation } from '../utils/locations';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

const message = (index: string, line: string) =>
`Verify this is the index that was intended; "${index}" was already set on line ${line}.`;

const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'Collection elements should not be replaced unconditionally',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
// internal parameter
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-empty-collection.ts
Expand Up @@ -28,6 +28,7 @@ import {
ancestorsChain,
} from '../utils';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

// Methods that mutate the collection but can't add elements
const nonAdditiveMutatorMethods = [
Expand Down Expand Up @@ -82,6 +83,12 @@ const strictlyReadingMethods = new Set([
const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'Empty collections should not be accessed or iterated',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
},
create(context: Rule.RuleContext) {
return {
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-extra-arguments.ts
Expand Up @@ -34,10 +34,17 @@ import {
IssueLocation,
} from '../utils/locations';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'Function calls should not pass extra arguments',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
// internal parameter
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-gratuitous-expressions.ts
Expand Up @@ -22,10 +22,17 @@ import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils';
import { EncodedMessage } from '../utils/locations';
import { isIdentifier, isIfStatement } from '../utils/nodes';
import { Rule } from '../utils/types';
import docsUrl from '../utils/docs-url';

const rule: Rule.RuleModule = {
meta: {
type: 'suggestion',
docs: {
description: 'Boolean expressions should not be gratuitous',
category: 'Best Practices',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
// internal parameter for rules having secondary locations
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-identical-conditions.ts
Expand Up @@ -23,10 +23,17 @@ import { Rule } from '../utils/types';
import { isIfStatement } from '../utils/nodes';
import { areEquivalent } from '../utils/equivalence';
import { report, issueLocation } from '../utils/locations';
import docsUrl from '../utils/docs-url';

const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'Related "if/else if" statements should not have the same condition',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
// internal parameter
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-identical-expressions.ts
Expand Up @@ -24,6 +24,7 @@ import { Rule } from '../utils/types';
import { isIdentifier, isLiteral } from '../utils/nodes';
import { areEquivalent } from '../utils/equivalence';
import { report, issueLocation, IssueLocation } from '../utils/locations';
import docsUrl from '../utils/docs-url';

const EQUALITY_OPERATOR_TOKEN_KINDS = new Set(['==', '===', '!=', '!==']);

Expand Down Expand Up @@ -62,6 +63,12 @@ function isOneOntoOneShifting(node: TSESTree.BinaryExpression | TSESTree.Logical
const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'Identical expressions should not be used on both sides of a binary operator',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
// internal parameter
Expand Down
7 changes: 7 additions & 0 deletions src/rules/no-identical-functions.ts
Expand Up @@ -23,6 +23,7 @@ import { TSESTree } from '@typescript-eslint/experimental-utils';
import { Rule } from '../utils/types';
import { areEquivalent } from '../utils/equivalence';
import { getMainFunctionTokenLocation, report, issueLocation } from '../utils/locations';
import docsUrl from '../utils/docs-url';

const message = (line: string) =>
`Update this function so that its implementation is not identical to the one on line ${line}.`;
Expand All @@ -35,6 +36,12 @@ type Function =
const rule: Rule.RuleModule = {
meta: {
type: 'problem',
docs: {
description: 'Functions should not have identical implementations',
category: 'Possible Errors',
recommended: 'error',
url: docsUrl(__filename),
},
schema: [
{
enum: ['sonar-runtime'],
Expand Down