Skip to content

Commit

Permalink
Create rule S6791: Disallow usage of unsafe lifecycle methods (`react…
Browse files Browse the repository at this point in the history
…/no-unsafe`) (#4362)
  • Loading branch information
yassin-kammoun-sonarsource authored Nov 8, 2023
1 parent fb49e29 commit b4fa76d
Show file tree
Hide file tree
Showing 15 changed files with 562 additions and 0 deletions.
14 changes: 14 additions & 0 deletions its/ruling/src/test/expected/jsts/Joust/typescript-S6791.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Joust:ts/components/EventLog.tsx": [
40
],
"Joust:ts/components/EventLogLine.tsx": [
42
],
"Joust:ts/components/MessagePicker.tsx": [
30
],
"Joust:ts/components/Scrubber.tsx": [
68
]
}
91 changes: 91 additions & 0 deletions its/ruling/src/test/expected/jsts/console/typescript-S6791.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"console:src/components/NodeSelector/NodeSelector.tsx": [
54
],
"console:src/components/RedirectOnMount/RedirectOnMount.tsx": [
23
],
"console:src/components/ResizableBox.tsx": [
39
],
"console:src/components/ScrollBox/ScrollBox.tsx": [
22
],
"console:src/views/ActionsView/ActionBoxes.tsx": [
99,
103
],
"console:src/views/AfterSignUpView/AfterSignUpView.tsx": [
87
],
"console:src/views/FunctionsView/FunctionPopup/RequestPipelineFunctionInput.tsx": [
87
],
"console:src/views/FunctionsView/FunctionPopup/TestPopup.tsx": [
88
],
"console:src/views/FunctionsView/FunctionRow.tsx": [
42
],
"console:src/views/Integrations/Algolia/AlgoliaQuery.tsx": [
60
],
"console:src/views/Integrations/AlgoliaPopup/AlgoliaIndexPopup/AlgoliaIndexPopupQuery.tsx": [
77
],
"console:src/views/ProjectRootView/ProjectRootView.tsx": [
110
],
"console:src/views/ProjectRootView/RootRedirectView.tsx": [
24
],
"console:src/views/ProjectRootView/TokenRedirectView.tsx": [
12
],
"console:src/views/RootView/RootView.tsx": [
24
],
"console:src/views/SchemaView/EnumsOverview/EnumBox.tsx": [
52
],
"console:src/views/SchemaView/SchemaEditor.tsx": [
104
],
"console:src/views/SchemaView/SchemaOverview/TypeBox.tsx": [
52
],
"console:src/views/models/AuthProviderPopup/AuthProviderPopup.tsx": [
32
],
"console:src/views/models/AuthProviderPopup/AuthProviderSidePanel.tsx": [
65
],
"console:src/views/models/DatabrowserView/Cell.tsx": [
125
],
"console:src/views/models/DatabrowserView/Cell/EnumCell.tsx": [
23
],
"console:src/views/models/DatabrowserView/Cell/FloatCell.tsx": [
14
],
"console:src/views/models/DatabrowserView/Cell/IntCell.tsx": [
15
],
"console:src/views/models/DatabrowserView/Cell/SelectNodesCell/SelectNodesCell.tsx": [
83
],
"console:src/views/models/DatabrowserView/Cell/StringCell.tsx": [
35
],
"console:src/views/models/DatabrowserView/DatabrowserView.tsx": [
170,
216
],
"console:src/views/models/ModelRedirectView.tsx": [
16
],
"console:src/views/playground/PlaygroundView/PlaygroundView.tsx": [
142
]
}
107 changes: 107 additions & 0 deletions its/ruling/src/test/expected/jsts/desktop/typescript-S6791.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
{
"desktop:app/src/ui/app-error.tsx": [
61
],
"desktop:app/src/ui/app-menu/app-menu-bar.tsx": [
119
],
"desktop:app/src/ui/app-menu/app-menu.tsx": [
340
],
"desktop:app/src/ui/app-menu/menu-pane.tsx": [
158
],
"desktop:app/src/ui/branches/branch-list.tsx": [
167
],
"desktop:app/src/ui/branches/pull-request-list.tsx": [
126
],
"desktop:app/src/ui/changes/changes-list.tsx": [
249
],
"desktop:app/src/ui/changes/commit-message.tsx": [
197
],
"desktop:app/src/ui/changes/sidebar.tsx": [
90
],
"desktop:app/src/ui/create-branch/create-branch-dialog.tsx": [
119
],
"desktop:app/src/ui/dialog/dialog.tsx": [
240
],
"desktop:app/src/ui/history/commit-list-item.tsx": [
82
],
"desktop:app/src/ui/history/commit-summary.tsx": [
261
],
"desktop:app/src/ui/history/compare.tsx": [
88,
134
],
"desktop:app/src/ui/history/selected-commit.tsx": [
118
],
"desktop:app/src/ui/lib/author-input.tsx": [
488
],
"desktop:app/src/ui/lib/checkbox.tsx": [
51
],
"desktop:app/src/ui/lib/filter-list.tsx": [
191,
197
],
"desktop:app/src/ui/lib/list/list.tsx": [
767
],
"desktop:app/src/ui/lib/path-text.tsx": [
255
],
"desktop:app/src/ui/lib/select.tsx": [
36
],
"desktop:app/src/ui/lib/text-box.tsx": [
120,
133
],
"desktop:app/src/ui/lib/vertical-segmented-control/vertical-segmented-control.tsx": [
101,
111
],
"desktop:app/src/ui/preferences/integrations.tsx": [
36
],
"desktop:app/src/ui/preferences/preferences.tsx": [
131
],
"desktop:app/src/ui/publish-repository/publish-repository.tsx": [
45,
49
],
"desktop:app/src/ui/relative-time.tsx": [
135,
141
],
"desktop:app/src/ui/repository-settings/repository-settings.tsx": [
95
],
"desktop:app/src/ui/sign-in/sign-in.tsx": [
54
],
"desktop:app/src/ui/tutorial/tutorial-panel.tsx": [
90
],
"desktop:app/src/ui/welcome/welcome.tsx": [
67
],
"desktop:app/src/ui/window/window-controls.tsx": [
39
],
"desktop:app/src/ui/window/zoom-info.tsx": [
39
]
}
26 changes: 26 additions & 0 deletions its/ruling/src/test/expected/jsts/eigen/typescript-S6791.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"eigen:src/app/Components/Bidding/Context/TimeOffsetProvider.tsx": [
88
],
"eigen:src/app/Components/Countdown/DurationProvider.tsx": [
55
],
"eigen:src/app/Components/Portal.tsx": [
62
],
"eigen:src/app/Components/ScrollableTabBar.tsx": [
75
],
"eigen:src/app/Scenes/City/City.tsx": [
103
],
"eigen:src/app/Scenes/City/Components/AllEvents.tsx": [
45
],
"eigen:src/app/Scenes/Map/GlobalMap.tsx": [
209
],
"eigen:src/palette/animation/CssTransition.tsx": [
25
]
}
16 changes: 16 additions & 0 deletions its/ruling/src/test/expected/jsts/redux/javascript-S6791.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"redux:examples/async/containers/App.js": [
19
],
"redux:examples/real-world/components/Explore.js": [
12
],
"redux:examples/real-world/containers/RepoPage.js": [
21,
25
],
"redux:examples/real-world/containers/UserPage.js": [
22,
26
]
}
36 changes: 36 additions & 0 deletions packages/jsts/src/rules/S6791/decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2023 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/S6791/javascript

import { Rule /*, AST*/ } from 'eslint';
import * as estree from 'estree';
import { interceptReportForReact } from '../helpers';

export function decorate(rule: Rule.RuleModule): Rule.RuleModule {
rule.meta!.messages!['unsafeMethod'] = '{{method}} is unsafe for use in async rendering.';
return interceptReportForReact(rule, (context, descriptor) => {
const {
node: { key },
} = descriptor as unknown as {
node: estree.Property | estree.PropertyDefinition | estree.MethodDefinition;
};
context.report({ ...descriptor, loc: key.loc! });
});
}
23 changes: 23 additions & 0 deletions packages/jsts/src/rules/S6791/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2023 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 } from 'eslint-plugin-react';
import { decorate } from './decorator';

export const rule = decorate(rules['no-unsafe']);
56 changes: 56 additions & 0 deletions packages/jsts/src/rules/S6791/unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2023 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 { rule } from './';
import { TypeScriptRuleTester } from '../tools';

const ruleTester = new TypeScriptRuleTester();

ruleTester.run(
'The decorator should refine both message and location, and provide a quickfix',
rule,
{
valid: [
{
code: `
import * as React from 'react';
class Component extends React.Component {
componentWillMount() {}
}`,
},
],
invalid: [
{
code: `
import * as React from 'react';
class Component extends React.Component {
UNSAFE_componentWillMount() {}
}`,
errors: [
{
message: 'UNSAFE_componentWillMount is unsafe for use in async rendering.',
line: 4,
column: 5,
endColumn: 30,
},
],
},
],
},
);
2 changes: 2 additions & 0 deletions packages/jsts/src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ import { rule as S2681 } from './S2681'; // no-unenclosed-multiline-block
import { rule as S6486 } from './S6486'; // no-uniq-key
import { rule as S6747 } from './S6747'; // no-unknown-property
import { rule as S1763 } from './S1763'; // no-unreachable
import { rule as S6791 } from './S6791'; // no-unsafe
import { rule as S5042 } from './S5042'; // no-unsafe-unzip
import { rule as S6478 } from './S6478'; // no-unstable-nested-components
import { rule as S3984 } from './S3984'; // no-unthrown-error
Expand Down Expand Up @@ -475,6 +476,7 @@ rules['no-unenclosed-multiline-block'] = S2681;
rules['no-uniq-key'] = S6486;
rules['no-unknown-property'] = S6747;
rules['no-unreachable'] = S1763;
rules['no-unsafe'] = S6791;
rules['no-unsafe-unzip'] = S5042;
rules['no-unstable-nested-components'] = S6478;
rules['no-unthrown-error'] = S3984;
Expand Down
Loading

0 comments on commit b4fa76d

Please sign in to comment.