Skip to content

Commit

Permalink
JS-54 Create rule S7060: Modules should not import themselves
Browse files Browse the repository at this point in the history
  • Loading branch information
saberduck committed Sep 11, 2024
1 parent 4b817fd commit 8fa51ed
Show file tree
Hide file tree
Showing 13 changed files with 262 additions and 2 deletions.
3 changes: 2 additions & 1 deletion packages/jsts/src/linter/quickfixes/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ export const quickFixRules = new Set([
'S1128',

// eslint-plugin-import
'S6859',
'S3863',
'S6859',
'S7060',
]);
12 changes: 12 additions & 0 deletions packages/jsts/src/rules/S7060/cb.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

import f from './cb.fixture.js'; // Noncompliant [[qf1]]
// fix@qf1 {{Remove this import}}
// edit@qf1 [[sc=0;ec=32]] {{}}

import f from './cb.fixture'; // Noncompliant

const f = require('./cb.fixture.js'); // Noncompliant [[qf2]]
// fix@qf2 {{Remove this require}}
// edit@qf2 [[sc=0;ec=37]] {{}}


28 changes: 28 additions & 0 deletions packages/jsts/src/rules/S7060/cb.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { check } from '../../../tests/tools';
import { rule } from './';
import path from 'path';

const sonarId = path.basename(__dirname);

describe('Rule S7060', () => {
check(sonarId, rule, __dirname);
});
74 changes: 74 additions & 0 deletions packages/jsts/src/rules/S7060/decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// https://sonarsource.github.io/rspec/#/rspec/S7060/javascript

import { Rule } from 'eslint';
import { generateMeta, interceptReport } from '../helpers';
import { meta } from './meta';
import * as estree from 'estree';

export function decorate(rule: Rule.RuleModule): Rule.RuleModule {
return interceptReport(
{
...rule,
meta: generateMeta(meta as Rule.RuleMetaData, {
...rule.meta!,
hasSuggestions: true,
}),
},
reportWithQuickFix,
);
}

function reportWithQuickFix(context: Rule.RuleContext, reportDescriptor: Rule.ReportDescriptor) {
if (!('node' in reportDescriptor)) {
return;
}
const { node } = reportDescriptor;
let suggestion: Rule.SuggestionReportDescriptor | undefined;
if (node.type === 'ImportDeclaration') {
suggestion = {
desc: 'Remove this import',
fix: fixer => fixer.remove(node),
};
} else if (node.type === 'CallExpression') {
const variableDecl = findRequireVariableDeclaration(node);
if (variableDecl) {
suggestion = {
desc: 'Remove this require',
fix: fixer => fixer.remove(variableDecl),
};
}
}
const rd = suggestion ? { ...reportDescriptor, suggest: [suggestion] } : reportDescriptor;
context.report(rd);
}

function findRequireVariableDeclaration(node: estree.Node) {
const parent = getParent(getParent(node));
if (parent.type === 'VariableDeclaration') {
return parent;
}
}

function getParent(node: estree.Node): estree.Node {
// @ts-ignore
return node.parent as estree.Node;
}
24 changes: 24 additions & 0 deletions packages/jsts/src/rules/S7060/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { rules as importRules } from 'eslint-plugin-import';
import { decorate } from './decorator';

export const rule = decorate(importRules['no-self-import']);
33 changes: 33 additions & 0 deletions packages/jsts/src/rules/S7060/meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

// DO NOT EDIT! This file is autogenerated by "npm run generate-meta"

export const meta = {
type: 'suggestion',
docs: {
description: 'Module should not import itself',
recommended: true,
url: 'https://sonarsource.github.io/rspec/#/rspec/S7060/javascript',
requiresTypeChecking: false,
},
};

export const sonarKey = 'S7060';
2 changes: 2 additions & 0 deletions packages/jsts/src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ import { rule as S4324 } from './S4324'; // no-return-type-any
import { rule as S5863 } from './S5863'; // no-same-argument-assert
import { rule as S3972 } from './S3972'; // no-same-line-conditional
import { rule as S6679 } from './S6679'; // no-self-compare
import { rule as S7060 } from './S7060'; // no-self-import
import { rule as S1607 } from './S1607'; // no-skipped-tests
import { rule as S1301 } from './S1301'; // no-small-switch
import { rule as S105 } from './S105'; // no-tab
Expand Down Expand Up @@ -785,6 +786,7 @@ const bridgeRules: { [key: string]: Rule.RuleModule } = {
S6958,
S6959,
S7059,
S7060,
S878: eslintRules['no-sequences'],
S881,
S888,
Expand Down
2 changes: 2 additions & 0 deletions packages/jsts/src/rules/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ import { rule as S2755 } from './S2755';
import { rule as S4817 } from './S4817';
import { rule as S6627 } from './S6627';
import { rule as S1607 } from './S1607';
import { rule as S7060 } from './S7060';
import type { Rule, Linter } from 'eslint';
import { rule as S7059 } from './S7059';

Expand Down Expand Up @@ -555,6 +556,7 @@ export const rules: Record<string, Rule.RuleModule> = {
'no-same-argument-assert': S5863,
'no-same-line-conditional': S3972,
'no-self-compare': S6679,
'no-self-import': S7060,
'no-skipped-test': S1607,
'no-small-switch': S1301,
'no-tab': S105,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ public static List<Class<? extends JavaScriptCheck>> getAllChecks() {
NoReturnTypeAnyCheck.class,
NoSameArgumentAssertCheck.class,
NoSelfCompareCheck.class,
NoSelfImportCheck.class,
NoSkippedTestsCheck.class,
NoSparseArraysCheck.class,
NoStaticElementInteractionsCheck.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.javascript.checks;

import org.sonar.check.Rule;
import org.sonar.plugins.javascript.api.Check;
import org.sonar.plugins.javascript.api.JavaScriptRule;
import org.sonar.plugins.javascript.api.TypeScriptRule;

@TypeScriptRule
@JavaScriptRule
@Rule(key = "S7060")
public class NoSelfImportCheck extends Check {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<h2>Why is this an issue?</h2>
<p>When a module imports itself it has no effect. This means that the import statement does nothing useful and serves no purpose. This can happen
during refactoring or when a developer mistakenly imports the module itself.</p>
<p>To fix the problem remove the self-import statement.</p>
<pre>
// file: foo.js
import foo from './foo'; // Noncompliant

const foo = require('./foo'); // Noncompliant
</pre>
<pre>
// file: index.js
import index from '.'; // Noncompliant

const index = require('.'); // Noncompliant
</pre>
<h2>Resources</h2>
<h3>Documentation</h3>
<ul>
<li> MDN web docs - <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules">Modules</a> </li>
<li> MDN web docs - <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">import</a> </li>
<li> Node.js docs - <a href="https://nodejs.org/api/modules.html#requireid">Node.js require</a> </li>
</ul>

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"title": "Module should not import itself",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "5min"
},
"tags": [],
"defaultSeverity": "Major",
"ruleSpecification": "RSPEC-7060",
"sqKey": "S7060",
"scope": "All",
"quickfix": "covered",
"code": {
"impacts": {
"MAINTAINABILITY": "MEDIUM",
"RELIABILITY": "MEDIUM"
},
"attribute": "MODULAR"
},
"compatibleLanguages": [
"JAVASCRIPT",
"TYPESCRIPT"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@
"S6957",
"S6958",
"S6959",
"S7059"
"S7059",
"S7060"
]
}

0 comments on commit 8fa51ed

Please sign in to comment.