diff --git a/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts b/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts index 6195e4ccd9..446ea13622 100644 --- a/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts +++ b/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts @@ -11,7 +11,7 @@ contract test1 { address test = tx.origin; } contract test2 {} contract TooMuchGas { uint x; - fallback() external { + fallback() external { x++; uint test; uint test1; @@ -43,18 +43,18 @@ module.exports = { .click('*[id="staticAnalysisRunBtn"]') .waitForElementPresent('#staticanalysisresult .warning', 5000) // Check warning count - .click('*[data-rb-event-key="basic"]') - .assert.containsText('*[data-id="StaticAnalysisErrorCount"]', '1') + .click('*[data-rb-event-key="remix"]') + .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount"]', '1') .verify.elementPresent('input[name="showLibWarnings"]') .verify.not.elementPresent('input[name="showLibWarnings"]:checked') .verify.elementPresent('label[id="headingshowLibWarnings"]') .click('label[id="headingshowLibWarnings"]') .pause(1000) - .click('*[data-rb-event-key="basic"]') - .assert.containsText('*[data-id="StaticAnalysisErrorCount"]', '382') + .click('*[data-rb-event-key="remix"]') + .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount', '382') .click('label[id="headingshowLibWarnings"]') .pause(1000) - .assert.containsText('*[data-id="StaticAnalysisErrorCount"]', '1') + .assert.containsText('span#ssaRemixtab > *[data-id="RemixStaticAnalysisErrorCount', '1') .end() } } diff --git a/apps/remix-ide/src/app/tabs/analysis-tab.js b/apps/remix-ide/src/app/tabs/analysis-tab.js index d718943408..250cd482b3 100644 --- a/apps/remix-ide/src/app/tabs/analysis-tab.js +++ b/apps/remix-ide/src/app/tabs/analysis-tab.js @@ -37,6 +37,7 @@ class AnalysisTab extends ViewPlugin { 'offsettolinecolumnconverter').api } this.dispatch = null + this.hints = [] } async onActivation () { @@ -47,10 +48,19 @@ class AnalysisTab extends ViewPlugin { } this.event.register('staticAnaysisWarning', (count) => { + let payloadType = '' + const error = this.hints.find(hint => hint.type === 'error') + const warning = this.hints.find(hints => hints.type === 'warning') + if (error) { + payloadType = 'error' + } else { + payloadType = 'warning' + } + if (count > 0) { - this.emit('statusChanged', { key: count, title: `${count} warning${count === 1 ? '' : 's'}`, type: 'warning' }) + this.emit('statusChanged', { key: count, title: payloadType === 'error' ? `You have some problem${count === 1 ? '' : 's'}` : 'You have some warnings', type: payloadType }) } else if (count === 0) { - this.emit('statusChanged', { key: 'succeed', title: 'no warning', type: 'success' }) + this.emit('statusChanged', { key: 'succeed', title: 'no warnings or errors', type: 'success' }) } else { // count ==-1 no compilation result this.emit('statusChanged', { key: 'none' }) diff --git a/apps/solhint/src/app/SolhintPluginClient.ts b/apps/solhint/src/app/SolhintPluginClient.ts index 8cfef7fbe2..e386096114 100644 --- a/apps/solhint/src/app/SolhintPluginClient.ts +++ b/apps/solhint/src/app/SolhintPluginClient.ts @@ -85,10 +85,14 @@ export class SolHint extends PluginClient { const reports: Array = reporters.reports const hints = reports.map((report: Report) => { return { - formattedMessage: `${report.message}\n${report.fix ? report.fix : ''}`, + formattedMessage: `${report.message}\n ${report.fix ? report.fix : ''}`, type: this.severity[report.severity] || 'error', column: report.column, - line: report.line - 1 + line: report.line - 1, + message: report.message, + ruleId: report.ruleId, + severity: report.severity, + fix: report.fix } }) diff --git a/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts b/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts index bf2bdfb8f0..1ace7d5ff3 100644 --- a/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts +++ b/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts @@ -44,24 +44,22 @@ export const compilation = (analysisModule: AnalysisTab, */ // eslint-disable-next-line @typescript-eslint/no-unused-vars export async function run (lastCompilationResult, lastCompilationSource, currentFile: string, state: RemixUiStaticAnalyserState, props: RemixUiStaticAnalyserProps, isSupportedVersion, showSlither, categoryIndex: number[], groupedModules, runner, _paq, message, showWarnings, allWarnings: React.RefObject, warningContainer: React.RefObject, calculateWarningStateEntries: (e:[string, any][]) => {length: number, errors: any[] }, warningState, setHints: React.Dispatch>, hints: SolHintReport[], setSlitherWarnings: React.Dispatch>, setSsaWarnings: React.Dispatch>, -slitherEnabled: boolean, setStartAnalysis: React.Dispatch>) { +slitherEnabled: boolean, setStartAnalysis: React.Dispatch>, solhintEnabled: boolean, basicEnabled: boolean) { setStartAnalysis(true) setHints([]) setSsaWarnings([]) setSlitherWarnings([]) if (!isSupportedVersion) return if (state.data !== null) { - if (lastCompilationResult && (categoryIndex.length > 0 || showSlither)) { + if (lastCompilationResult && (solhintEnabled || basicEnabled || showSlither)) { const warningMessage = [] const warningErrors = [] - + props.analysisModule.hints = [] // Run solhint + _paq.push(['trackEvent', 'solidityStaticAnalyzer', 'analyze', 'solHint']) const hintsResult = await props.analysisModule.call('solhint', 'lint', state.file) + props.analysisModule.hints = solhintEnabled === false ? 0 : hintsResult setHints(hintsResult) - const warningResult = calculateWarningStateEntries(Object.entries(warningState)) - props.analysisModule.emit('statusChanged', { key: hints.length+warningResult.length, - title: `${hints.length+warningResult.length} warning${hints.length+warningResult.length === 1 ? '' : 's'}`, type: 'warning'}) - // Remix Analysis _paq.push(['trackEvent', 'solidityStaticAnalyzer', 'analyze', 'remixAnalyzer']) const results = runner.run(lastCompilationResult, categoryIndex) diff --git a/libs/remix-ui/static-analyser/src/lib/components/BasicTitle.tsx b/libs/remix-ui/static-analyser/src/lib/components/BasicTitle.tsx index 51a539418d..ff7b24b587 100644 --- a/libs/remix-ui/static-analyser/src/lib/components/BasicTitle.tsx +++ b/libs/remix-ui/static-analyser/src/lib/components/BasicTitle.tsx @@ -1,9 +1,11 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import { ErrorRendererOptions } from '../../staticanalyser' type BasicTitleProps = { warningStateEntries: any + ssaWarnings: any[] hideWarnings?: boolean + showLibsWarnings?: boolean } type warningResultOption = { @@ -30,15 +32,22 @@ export function calculateWarningStateEntries(entries: [string, any][]) { } export function BasicTitle(props: BasicTitleProps) { + const [filteredTotal, setFilteredTotal] = useState(0) + + useEffect(() => { + setFilteredTotal(props.ssaWarnings.filter(x => !x.options.isLibrary && x.hasWarning).length) + }, [props, props.ssaWarnings.filter(x => !x.options.isLibrary && x.hasWarning).length]) return ( - Remix{props.warningStateEntries.length > 0 ? !props.hideWarnings ? 0 ? 'badge-warning' : 'badge-danger'} rounded-circle ml-1 text-center`}>{calculateWarningStateEntries(props.warningStateEntries).length}: ( - + Remix{props.ssaWarnings.length > 0 ? !props.hideWarnings ? !props.showLibsWarnings ? x.hasWarning).length > 0 ? 'badge-warning' : props.ssaWarnings.filter(x => x.options.type === 'errors').length > 0 ? 'badge-danger' : 'badge-info'} badge-pill mx-1 ml-1 text-center`}> + {filteredTotal} + : ( + x.options.type !== 'warning' && x.options.type !== 'error').length > 0 ? 'badge-info' : props.ssaWarnings.filter(x => x.options.type === 'errors').length > 0 ? 'badge-danger' : 'badge-warning'} badge-pill mx-1 ml-1 text-center`}> { - calculateWarningStateEntries(props.warningStateEntries).errors.length + props.ssaWarnings.length } - - ) : null} + + ) : null : null} ) } diff --git a/libs/remix-ui/static-analyser/src/lib/reducers/staticAnalysisReducer.ts b/libs/remix-ui/static-analyser/src/lib/reducers/staticAnalysisReducer.ts index 1e12b09f03..001d9cc80a 100644 --- a/libs/remix-ui/static-analyser/src/lib/reducers/staticAnalysisReducer.ts +++ b/libs/remix-ui/static-analyser/src/lib/reducers/staticAnalysisReducer.ts @@ -1,3 +1,4 @@ +import { CompilationResult, SourceWithTarget } from "@remixproject/plugin-api" import { RemixUiStaticAnalyserReducerActionType, RemixUiStaticAnalyserState } from "../../staticanalyser" export const initialState: RemixUiStaticAnalyserState = { @@ -26,3 +27,12 @@ export const analysisReducer = (state: RemixUiStaticAnalyserState, return initialState } } + +type someReducerState = { + solhintEnabled?: boolean + basicEnabled?: boolean + slitherEnabled?: boolean + isSupportedVersion?: boolean + compiledState?: { data: CompilationResult, langVersion: string, fileName: string, source: SourceWithTarget, input: string } +} + diff --git a/libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx b/libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx index 603b87ad08..e38a4daaf1 100644 --- a/libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx +++ b/libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx @@ -1,91 +1,108 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unused-vars */ -import React, { useEffect, useState, useReducer, useRef, Fragment } from 'react' // eslint-disable-line -import Button from './Button/StaticAnalyserButton' // eslint-disable-line -import { util } from '@remix-project/remix-lib' -import _ from 'lodash' -import * as semver from 'semver' -import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line -import { RemixUiCheckbox } from '@remix-ui/checkbox' // eslint-disable-line -import ErrorRenderer from './ErrorRenderer' // eslint-disable-line -import { compilation } from './actions/staticAnalysisActions' -import { initialState, analysisReducer } from './reducers/staticAnalysisReducer' -import { CodeAnalysis } from '@remix-project/remix-analyzer' -import Tab from 'react-bootstrap/Tab' -import Tabs from 'react-bootstrap/Tabs' -import { AnalysisTab, SolHintReport } from '../staticanalyser' -import { run } from './actions/staticAnalysisActions' -import { BasicTitle, calculateWarningStateEntries } from './components/BasicTitle' +import React, { + useEffect, + useState, + useReducer, + useRef, + Fragment, +} from "react"; // eslint-disable-line +import Button from "./Button/StaticAnalyserButton"; // eslint-disable-line +import { util } from "@remix-project/remix-lib"; +import _ from "lodash"; +import * as semver from "semver"; +import { TreeView, TreeViewItem } from "@remix-ui/tree-view"; // eslint-disable-line +import { RemixUiCheckbox } from "@remix-ui/checkbox"; // eslint-disable-line +import ErrorRenderer from "./ErrorRenderer"; // eslint-disable-line +import { compilation } from "./actions/staticAnalysisActions"; +import { + initialState, + analysisReducer, +} from "./reducers/staticAnalysisReducer"; +import { CodeAnalysis } from "@remix-project/remix-analyzer"; +import Tab from "react-bootstrap/Tab"; +import Tabs from "react-bootstrap/Tabs"; +import { AnalysisTab, SolHintReport } from "../staticanalyser"; +import { run } from "./actions/staticAnalysisActions"; +import { + BasicTitle, + calculateWarningStateEntries, +} from "./components/BasicTitle"; +import { Nav, TabContainer } from "react-bootstrap"; declare global { interface Window { - _paq: any + _paq: any; } } -const _paq = window._paq = window._paq || [] //eslint-disable-line +const _paq = (window._paq = window._paq || []); //eslint-disable-line /* eslint-disable-next-line */ export interface RemixUiStaticAnalyserProps { - registry: any, - event: any, - analysisModule: AnalysisTab + registry: any; + event: any; + analysisModule: AnalysisTab; } +type tabSelectionType = "remix" | "solhint" | "slither" | "none"; + export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { - const [runner] = useState(new CodeAnalysis()) + const [runner] = useState(new CodeAnalysis()); const preProcessModules = (arr: any) => { return arr.map((Item, i) => { - const itemObj = new Item() - itemObj._index = i - itemObj.categoryDisplayName = itemObj.category.displayName - itemObj.categoryId = itemObj.category.id - return itemObj - }) - } + const itemObj = new Item(); + itemObj._index = i; + itemObj.categoryDisplayName = itemObj.category.displayName; + itemObj.categoryId = itemObj.category.id; + return itemObj; + }); + }; const groupedModules = util.groupBy( preProcessModules(runner.modules()), - 'categoryId' - ) + "categoryId" + ); const getIndex = (modules, array) => { - Object.values(modules).map((value: {_index}) => { + Object.values(modules).map((value: { _index }) => { if (Array.isArray(value)) { value.forEach((x) => { - array.push(x._index.toString()) - }) + array.push(x._index.toString()); + }); } else { - array.push(value._index.toString()) + array.push(value._index.toString()); } - }) - } + }); + }; const groupedModuleIndex = (modules) => { - const indexOfCategory = [] + const indexOfCategory = []; if (!_.isEmpty(modules)) { - getIndex(modules, indexOfCategory) + getIndex(modules, indexOfCategory); } - return indexOfCategory - } - const [basicEnabled, setBasicEnabled] = useState(true) - const [solhintEnabled, setSolhintEnabled] = useState(true) // assuming that solhint is always enabled - const [showSlither, setShowSlither] = useState(false) - const [slitherEnabled, setSlitherEnabled] = useState(false) - const [startAnalysis, setStartAnalysis] = useState(false) - const [isSupportedVersion, setIsSupportedVersion] = useState(false) - let [showLibsWarning, setShowLibsWarning] = useState(false) // eslint-disable-line prefer-const - const [categoryIndex, setCategoryIndex] = useState(groupedModuleIndex(groupedModules)) - const [warningState, setWarningState] = useState({}) - const [hideWarnings, setHideWarnings] = useState(false) - const [hints, setHints] = useState([]) - const [slitherWarnings, setSlitherWarnings] = useState([]) - const [ssaWarnings, setSsaWarnings] = useState([]) - - const warningContainer = useRef(null) - const allWarnings = useRef({}) - const [state, dispatch] = useReducer(analysisReducer, initialState) - const [runButtonTitle, setRunButtonTitle] = useState(`Run analysis`) + return indexOfCategory; + }; + const [basicEnabled, setBasicEnabled] = useState(true); + const [solhintEnabled, setSolhintEnabled] = useState(true); // assuming that solhint is always enabled + const [showSlither, setShowSlither] = useState(false); + const [slitherEnabled, setSlitherEnabled] = useState(false); + const [startAnalysis, setStartAnalysis] = useState(false); + const [isSupportedVersion, setIsSupportedVersion] = useState(false); + let [showLibsWarning, setShowLibsWarning] = useState(false); // eslint-disable-line prefer-const + const [categoryIndex, setCategoryIndex] = useState( + groupedModuleIndex(groupedModules) + ); + const [warningState, setWarningState] = useState({}); + const [hideWarnings, setHideWarnings] = useState(false); + const [hints, setHints] = useState([]); + const [slitherWarnings, setSlitherWarnings] = useState([]); + const [ssaWarnings, setSsaWarnings] = useState([]); + const [selectedTab, setSelectedTab] = useState("remix"); + const warningContainer = useRef(null); + const allWarnings = useRef({}); + const [state, dispatch] = useReducer(analysisReducer, initialState); + const [runButtonTitle, setRunButtonTitle] = useState(`Run analysis`); /** * Disable static analysis for contracts whose compiler version is @@ -94,228 +111,244 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { */ const setDisableForRun = (version: string) => { const truncateVersion = (version: string) => { - const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version) - return tmp ? tmp[1] : version - } - if (version && version != '' && !semver.gt(truncateVersion(version), '0.4.12')) { - setIsSupportedVersion(false) - setRunButtonTitle('Select Solidity compiler version greater than 0.4.12.') + const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version); + return tmp ? tmp[1] : version; + }; + if ( + version && + version != "" && + !semver.gt(truncateVersion(version), "0.4.12") + ) { + setIsSupportedVersion(false); + setRunButtonTitle( + "Select Solidity compiler version greater than 0.4.12." + ); } else { - setIsSupportedVersion(true) - setRunButtonTitle(`${state && state.data && state.file.length > 0 ? 'Run analysis': 'To run analysis tools, first compile a contract.'}`) + setIsSupportedVersion(true); + setRunButtonTitle( + `${ + state && state.data && state.file.length > 0 + ? "Run analysis" + : "To run analysis tools, first compile a contract." + }` + ); } - } + }; useEffect(() => { - compilation(props.analysisModule, dispatch) - }, [props]) + compilation(props.analysisModule, dispatch); + }, [props]); useEffect(() => { - setWarningState({}) - const runAnalysis = async () => { - await run(state.data, state.source, state.file, state, props, isSupportedVersion, showSlither, categoryIndex, groupedModules, runner,_paq, message, showWarnings, allWarnings, warningContainer,calculateWarningStateEntries, warningState, setHints, hints, setSlitherWarnings, setSsaWarnings, slitherEnabled, setStartAnalysis) - } - props.event.trigger('staticAnaysisWarning', []) - return () => { } - }, [state]) + props.analysisModule + .call("solidity", "getCompilerState") + .then((compilerState) => setDisableForRun(compilerState.currentVersion)); + props.event.trigger("staticAnalysisWarning", [-1]); + }, []); useEffect(() => { - props.analysisModule.call('solidity', 'getCompilerState').then((compilerState) => setDisableForRun(compilerState.currentVersion)) - }, []) + props.event.trigger("staticAnalysisWarning", [-1]); + }, [state]); + + useEffect(() => { + props.analysisModule.on( + "solidity", + "compilationFinished", + (fileName, source, languageVersion, data) => { + setHints([]); + setSlitherWarnings([]); + setSsaWarnings([]); + } + ); + }, [state]); useEffect(() => { const checkRemixdActive = async () => { - const remixdActive = await props.analysisModule.call('manager', 'isActive', 'remixd') + const remixdActive = await props.analysisModule.call( + "manager", + "isActive", + "remixd" + ); if (remixdActive) { - setSlitherEnabled(true) - setShowSlither(true) + setSlitherEnabled(true); + setShowSlither(true); } - } - checkRemixdActive() - }, [props]) + }; + checkRemixdActive(); + props.event.trigger("staticAnalysisWarning", [-1]); + }, [props]); useEffect(() => { - props.analysisModule.on('filePanel', 'setWorkspace', (currentWorkspace) => { + props.analysisModule.on("filePanel", "setWorkspace", (currentWorkspace) => { // Reset warning state - setWarningState([]) + setWarningState([]); // Reset badge - props.event.trigger('staticAnaysisWarning', []) + // Reset state - dispatch({ type: '', payload: initialState }) - setHints([]) - setSlitherWarnings([]) - setSsaWarnings([]) + dispatch({ type: "", payload: initialState }); + setHints([]); + setSlitherWarnings([]); + setSsaWarnings([]); // Show 'Enable Slither Analysis' checkbox if (currentWorkspace && currentWorkspace.isLocalhost === true) { - setShowSlither(true) - setSlitherEnabled(true) - } - else { - setShowSlither(false) - setSlitherEnabled(false) + setShowSlither(true); + setSlitherEnabled(true); + } else { + setShowSlither(false); + setSlitherEnabled(false); } - }) - props.analysisModule.on('manager', 'pluginDeactivated', (plugin) => { + setTimeout(() => { + props.event.trigger("staticAnalysisWarning", [-1]); + }, 500); + }); + props.analysisModule.on("manager", "pluginDeactivated", (plugin) => { // Hide 'Enable Slither Analysis' checkbox - if (plugin.name === 'remixd') { + if (plugin.name === "remixd") { // Reset warning state - setWarningState([]) - setHints([]) - setSlitherWarnings([]) - setSlitherEnabled(false) - setSsaWarnings([]) + setWarningState([]); + setHints([]); + setSlitherWarnings([]); + setSlitherEnabled(false); + setSsaWarnings([]); // Reset badge - props.event.trigger('staticAnaysisWarning', []) + props.event.trigger("staticAnalysisWarning", [-1]); // Reset state - dispatch({ type: '', payload: initialState }) - setShowSlither(false) + dispatch({ type: "", payload: initialState }); + setShowSlither(false); } - }) + }); // eslint-disable-next-line @typescript-eslint/no-unused-vars - props.analysisModule.on('solidity', 'compilerLoaded', async (version: string, license: string) => { - setDisableForRun(version) - }) - return () => { } - }, [props]) - - const message = (name: string, warning: any, more?: string, fileName?: string, locationString?: string) : string => { - return (` + props.analysisModule.on( + "solidity", + "compilerLoaded", + async (version: string, license: string) => { + setDisableForRun(version); + props.event.trigger("staticAnalysisWarning", [-1]); + } + ); + return () => {}; + }, [props]); + + const hintErrors = hints.filter((hint) => hint.type === "error"); + const noLibSlitherWarnings = slitherWarnings.filter( + (w) => !w.options.isLibrary + ); + const slitherErrors = noLibSlitherWarnings.filter( + (slitherError) => slitherError.options.type === "error" + ); + const remixAnalysisNoLibs = ssaWarnings.filter( + (ssa) => ssa.options.isLibrary === false + ); + const remixAnalysisLessWarnings = ssaWarnings.filter( + (ssa) => ssa.options.type !== "warning" + ); + + const message = ( + name: string, + warning: any, + more?: string, + fileName?: string, + locationString?: string + ): string => { + return ` ${name} ${warning} - ${more - ? (more) - : ( ) + ${ + more ? ( + + + more + + + ) : ( + + ) } Pos: ${locationString} - ` - ) - } + `; + }; const filterWarnings = () => { - let newWarningState = {} - let newWarningCount = 0 + let newWarningState = {}; + let newWarningCount = 0; if (showLibsWarning) { for (const category in allWarnings.current) - newWarningCount = newWarningCount + allWarnings.current[category].length - newWarningState = allWarnings.current - } - else { + newWarningCount = + newWarningCount + allWarnings.current[category].length; + newWarningState = allWarnings.current; + } else { for (const category in allWarnings.current) { - const warnings = allWarnings.current[category] - newWarningState[category] = [] + const warnings = allWarnings.current[category]; + newWarningState[category] = []; for (const warning of warnings) { if (!warning.options.isLibrary) { - newWarningCount++ - newWarningState[category].push(warning) + newWarningCount++; + newWarningState[category].push(warning); } } } } - props.event.trigger('staticAnaysisWarning', [newWarningCount]) - setWarningState(newWarningState) - } - - useEffect(() => { - if(hints.length > 0) { - props.event.trigger('staticAnaysisWarning', [hints.length]) - } - },[hints.length, state]) + props.event.trigger("staticAnaysisWarning", [newWarningCount]); + setWarningState(newWarningState); + }; const showWarnings = (warningMessage, groupByKey) => { - const resultArray = [] - warningMessage.map(x => { - resultArray.push(x) - }) - function groupBy (objectArray, property) { + const resultArray = []; + warningMessage.map((x) => { + resultArray.push(x); + }); + function groupBy(objectArray, property) { return objectArray.reduce((acc, obj) => { - const key = obj[property] + const key = obj[property]; if (!acc[key]) { - acc[key] = [] + acc[key] = []; } // Add object to list for given key's value - acc[key].push(obj) - return acc - }, {}) + acc[key].push(obj); + return acc; + }, {}); } - const groupedCategory = groupBy(resultArray, groupByKey) - allWarnings.current = groupedCategory - filterWarnings() - } - + const groupedCategory = groupBy(resultArray, groupByKey); + allWarnings.current = groupedCategory; + filterWarnings(); + }; const handleCheckAllModules = (groupedModules) => { - const index = groupedModuleIndex(groupedModules) - if (index.every(el => categoryIndex.includes(el))) { + const index = groupedModuleIndex(groupedModules); + if (index.every((el) => categoryIndex.includes(el))) { setCategoryIndex( categoryIndex.filter((el) => { - return !index.includes(el) + return !index.includes(el); }) - ) + ); } else { - setCategoryIndex(_.uniq([...categoryIndex, ...index])) + setCategoryIndex(_.uniq([...categoryIndex, ...index])); } - } + }; const handleCheckOrUncheckCategory = (category) => { - const index = groupedModuleIndex(category) - if (index.every(el => categoryIndex.includes(el))) { + const index = groupedModuleIndex(category); + if (index.every((el) => categoryIndex.includes(el))) { setCategoryIndex( categoryIndex.filter((el) => { - return !index.includes(el) + return !index.includes(el); }) - ) + ); } else { - setCategoryIndex(_.uniq([...categoryIndex, ...index])) - } - } - - const handleSlitherEnabled = async () => { - const checkRemixd = await props.analysisModule.call('manager', 'isActive', 'remixd') - if (showSlither) { - setShowSlither(false) + setCategoryIndex(_.uniq([...categoryIndex, ...index])); } - if(!showSlither) { - setShowSlither(true) - } - } - - const handleBasicEnabled = () => { - if (basicEnabled) { - setBasicEnabled(false) - } else { - setBasicEnabled(true) - } - } - - const handleLinterEnabled = () => { - if (solhintEnabled) { - setSolhintEnabled(false) - } else { - setSolhintEnabled(true) - } - } + }; const handleCheckSingle = (event, _index) => { - _index = _index.toString() + _index = _index.toString(); if (categoryIndex.includes(_index)) { - setCategoryIndex(categoryIndex.filter(val => val !== _index)) - } else { - setCategoryIndex(_.uniq([...categoryIndex, _index])) - } - } - - const handleShowLibsWarning = () => { - if (showLibsWarning) { - showLibsWarning = false - setShowLibsWarning(false) + setCategoryIndex(categoryIndex.filter((val) => val !== _index)); } else { - showLibsWarning = true - setShowLibsWarning(true) + setCategoryIndex(_.uniq([...categoryIndex, _index])); } - filterWarnings() - } + }; const categoryItem = (categoryId, item, i) => { return ( @@ -327,7 +360,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { name="checkSingleEntry" itemName={item.name} label={item.description} - onClick={event => handleCheckSingle(event, item._index)} + onClick={(event) => handleCheckSingle(event, item._index)} checked={categoryIndex.includes(item._index.toString())} onChange={() => {}} /> @@ -344,7 +377,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { label={