Skip to content

Commit

Permalink
Resolve JS-81
Browse files Browse the repository at this point in the history
  • Loading branch information
ericmorand-sonarsource committed May 3, 2024
1 parent e91895f commit 5843c5f
Show file tree
Hide file tree
Showing 88 changed files with 1,055 additions and 305 deletions.
23 changes: 20 additions & 3 deletions packages/jsts/src/rules/S100/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import { Rule } from 'eslint';
import * as estree from 'estree';
import { last, functionLike } from '../helpers';
import type { RuleModule } from '../../../../shared/src/types/rule';

interface FunctionKnowledge {
node: estree.Identifier;
Expand Down Expand Up @@ -52,15 +53,31 @@ const functionExpressionVariable = [
')',
].join('');

export const rule: Rule.RuleModule = {
export type Options = [
{
format: string;
},
];

export const rule: RuleModule<Options> = {
meta: {
messages: {
renameFunction:
"Rename this '{{function}}' function to match the regular expression '{{format}}'.",
},
schema: [
{
type: 'object',
properties: {
format: {
type: 'string',
},
},
},
],
},
create(context: Rule.RuleContext) {
const [{ format }] = context.options;
const [{ format }] = context.options as Options;
const knowledgeStack: FunctionKnowledge[] = [];
return {
[functionExpressionProperty]: (node: estree.Property) => {
Expand Down Expand Up @@ -111,7 +128,7 @@ export const rule: Rule.RuleModule = {
},
ReturnStatement: (node: estree.ReturnStatement) => {
const knowledge = last(knowledgeStack);
const ancestors = context.getAncestors();
const ancestors = context.sourceCode.getAncestors(node);

for (let i = ancestors.length - 1; i >= 0; i--) {
if (functionLike.has(ancestors[i].type)) {
Expand Down
19 changes: 18 additions & 1 deletion packages/jsts/src/rules/S101/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,31 @@
import { Rule } from 'eslint';
import * as estree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
import type { RuleModule } from '../../../../shared/src/types/rule';

type ClassOrInterfaceDeclaration = TSESTree.ClassDeclaration | TSESTree.TSInterfaceDeclaration;

export const rule: Rule.RuleModule = {
export type Options = [
{
format: string;
},
];

export const rule: RuleModule<Options> = {
meta: {
messages: {
renameClass: 'Rename {{symbolType}} "{{symbol}}" to match the regular expression {{format}}.',
},
schema: [
{
type: 'object',
properties: {
format: {
type: 'string',
},
},
},
],
},
create(context: Rule.RuleContext) {
return {
Expand Down
24 changes: 20 additions & 4 deletions packages/jsts/src/rules/S104/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,33 @@
import { Rule } from 'eslint';
import * as estree from 'estree';
import { getLocsNumber, getCommentLineNumbers } from '../S138/rule';
import type { RuleModule } from '../../../../shared/src/types/rule';

export const rule: Rule.RuleModule = {
export type Options = [
{
maximum: number;
},
];

export const rule: RuleModule<Options> = {
meta: {
messages: {
maxFileLine:
'This file has {{lineCount}} lines, which is greater than {{threshold}} authorized. Split it into smaller files.',
},
schema: [{ type: 'integer' }],
schema: [
{
type: 'object',
properties: {
maximum: {
type: 'integer',
},
},
},
],
},
create(context: Rule.RuleContext) {
const [threshold] = context.options;
const [{ maximum: threshold }] = context.options as Options;

const sourceCode = context.sourceCode;
const lines = sourceCode.lines;
Expand All @@ -52,7 +68,7 @@ export const rule: Rule.RuleModule = {
messageId: 'maxFileLine',
data: {
lineCount: lineCount.toString(),
threshold,
threshold: `${threshold}`,
},
loc: { line: 0, column: 0 },
});
Expand Down
11 changes: 8 additions & 3 deletions packages/jsts/src/rules/S104/unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
*/
import { RuleTester } from 'eslint';
import { rule } from './';
import type { Options } from './rule';

const createOptions = (maximum: number): Options => {
return [{ maximum }];
};

const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2018 } });
ruleTester.run('Too many lines in file', rule, {
Expand All @@ -27,15 +32,15 @@ ruleTester.run('Too many lines in file', rule, {
code: `a;
b;
c;`,
options: [3],
options: createOptions(3),
},
{
code: `a;
b;
// comment
c;`,
options: [3],
options: createOptions(3),
},
],
invalid: [
Expand All @@ -46,7 +51,7 @@ ruleTester.run('Too many lines in file', rule, {
c;
// comment
d;`,
options: [3],
options: createOptions(3),
errors: [
{
message: `This file has 4 lines, which is greater than 3 authorized. Split it into smaller files.`,
Expand Down
27 changes: 22 additions & 5 deletions packages/jsts/src/rules/S1067/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,36 @@ import * as estree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
import { toEncodedMessage } from '../helpers';
import { SONAR_RUNTIME } from '../../linter/parameters';
import type { RuleModule } from '../../../../shared/src/types/rule';

export const rule: Rule.RuleModule = {
export type Options = [
{
max: number;
},
string?,
];

export const rule: RuleModule<Options> = {
meta: {
schema: [
{ type: 'integer' },
{
type: 'object',
properties: {
max: {
type: 'integer',
},
},
},
{
type: 'string',
// internal parameter for rules having secondary locations
enum: [SONAR_RUNTIME],
},
],
},
create(context: Rule.RuleContext) {
const [max] = context.options;
const options = context.options as Options;
const threshold = options[0].max;
const statementLevel: ExpressionComplexity[] = [new ExpressionComplexity()];
return {
'*': (node: estree.Node) => {
Expand All @@ -56,8 +73,8 @@ export const rule: Rule.RuleModule = {
expr.decrementNestedExprLevel();
if (expr.isOnFirstExprLevel()) {
const operators = expr.getComplexityOperators();
if (operators.length > max) {
reportIssue(tree, operators, max, context);
if (operators.length > threshold) {
reportIssue(tree, operators, threshold, context);
}
expr.resetExpressionComplexityOperators();
}
Expand Down
51 changes: 34 additions & 17 deletions packages/jsts/src/rules/S1067/unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,70 +20,79 @@
import { RuleTester } from 'eslint';
import { rule } from './';
import { IssueLocation, EncodedMessage } from 'eslint-plugin-sonarjs/lib/utils/locations';
import type { Options } from './rule';

const ruleTester = new RuleTester({
parserOptions: { ecmaVersion: 2018, sourceType: 'module', ecmaFeatures: { jsx: true } },
});

const MAX = 3;
const options: Options = [
{
max: 3,
},
];

ruleTester.run('Expressions should not be too complex', rule, {
valid: [
{
code: `let b = 1 || 2 || 3 || 4`,
options: [MAX],
options,
},
{
code: `let b = 1 && 2 && 4 && 4`,
options: [MAX],
options,
},
{
code: `let b = 1 ? ( 2 ? ( 3 ? true : false ) : false ) : false;`,
options: [MAX],
options,
},
{
code: `let b = foo(1 || 2 || 3, 1 || 2 || 3);`,
options: [MAX],
options,
},
{
code: `let b = 1 || 2 || 3 || foo(1 || 2);`,
options: [MAX],
options,
},
{
code: `let b = {x: 1 || 2 || 3, y: 1 || 2 || 3};`,
options: [MAX],
options,
},
{
code: `let b = 1 || 2 || 3 || {x: 1 || 2};`,
options: [MAX],
options,
},
{
code: `let b = function () {1 || 2 || 3 || 4};`,
options: [MAX],
options,
},
{
code: `let b = 1 || 2 || 3 || function () {1 || 2};`,
options: [MAX],
options,
},
{
code: `let b = 1 || 2 || 3 || function () {1 || 2 || function () {1 || 2}};`,
options: [MAX],
options,
},
{
code: `let b = 1 || 2 || 3 || function f() {1 || 2 || function g() {1 || 2}};`,
options: [MAX],
options,
},
{
code: `let b = <div>{1 || 2 || 3 || 4}</div>;`,
options: [MAX],
options,
},
{
code: `let b = 1 || 2 || 3 || <div>{1 || 2}</div>;`,
options: [MAX],
options,
},
{
code: `let b = 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10;`,
options: [10],
options: [
{
threshold: 10,
},
],
},
],
invalid: [
Expand Down Expand Up @@ -132,7 +141,7 @@ ruleTester.run('Expressions should not be too complex', rule, {
],
});

function invalid(code: string, max = MAX) {
function invalid(code: string, max = 3) {
const issue = {
complexity: 0,
primaryLocation: {} as IssueLocation,
Expand Down Expand Up @@ -169,7 +178,15 @@ function invalid(code: string, max = MAX) {
}
}
issue.secondaryLocations.sort((a, b) => b.column - a.column);
return { code, errors: [error(issue, max)], options: [max] };
return {
code,
errors: [error(issue, max)],
options: [
{
max,
},
],
};
}

function error(
Expand Down
23 changes: 20 additions & 3 deletions packages/jsts/src/rules/S107/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,29 @@ import {
interceptReport,
mergeRules,
} from '../helpers';
import type { RuleModule } from '../../../../shared/src/types/rule';

const eslintMaxParams = eslintRules['max-params'];

export const rule: Rule.RuleModule = {
export type Options = [
{
maximumFunctionParameters: number;
},
];

export const rule: RuleModule<Options> = {
meta: {
messages: { ...eslintMaxParams.meta?.messages },
schema: [
{
type: 'object',
properties: {
maximumFunctionParameters: {
type: 'integer',
},
},
},
],
},
create(context: Rule.RuleContext) {
/**
Expand All @@ -45,7 +62,7 @@ export const rule: Rule.RuleModule = {
const ruleDecoration: Rule.RuleModule = interceptReport(
eslintMaxParams,
function (context: Rule.RuleContext, descriptor: Rule.ReportDescriptor) {
const maxParams = context.options[0] as number;
const maxParams = (context.options as Options)[0].maximumFunctionParameters;
if ('node' in descriptor) {
const functionLike = descriptor.node as TSESTree.FunctionLike;
if (!isException(functionLike)) {
Expand Down Expand Up @@ -119,7 +136,7 @@ export const rule: Rule.RuleModule = {

function checkFunction(node: estree.Node) {
const functionLike = node as unknown as TSESTree.FunctionLike;
const maxParams = context.options[0] as number;
const maxParams = (context.options as Options)[0].maximumFunctionParameters;
const numParams = functionLike.params.length;
if (numParams > maxParams) {
context.report({
Expand Down
Loading

0 comments on commit 5843c5f

Please sign in to comment.