fix eslint and update eslint to 8.0.0

This commit is contained in:
Rohid
2024-08-31 01:34:01 +06:00
parent a87b17e48c
commit d7cd69783b
27 changed files with 5875 additions and 3876 deletions

View File

@@ -8,18 +8,20 @@ module.exports = {
},
extends: [
'eslint:recommended',
'kentcdodds/best-practices',
'kentcdodds/es6/possible-errors',
// 'kentcdodds/best-practices',
// 'kentcdodds/es6/possible-errors',
'kentcdodds',
// 'kentcdodds/react',
'kentcdodds/import',
'kentcdodds/jest',
'kentcdodds/possible-errors',
// 'kentcdodds/possible-errors',
// 'plugin:@typescript-eslint/recommended',
'plugin:jest-dom/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/errors',
'plugin:import/typescript',
'plugin:prettier/recommended',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
// 'plugin:react/jsx-runtime',
'plugin:typescript-sort-keys/recommended',
'plugin:react-hooks/recommended',
],
@@ -36,7 +38,7 @@ module.exports = {
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
sourceType: 'module', // Allows for the use of imports
},
plugins: ['react', '@typescript-eslint', 'typescript-sort-keys', 'sort-keys-fix'],
plugins: ['react', 'typescript-sort-keys', 'sort-keys-fix'],
rules: {
'no-await-in-loop': 'off',
'prettier/prettier': 'error',

9581
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -74,8 +74,8 @@
"@types/uuid": "^10.0.0",
"@types/wait-on": "^5.2.0",
"@types/webextension-polyfill": "^0.10.0",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@xarc/run": "^1.0.4",
"axios": "^1.7.5",
"babel-jest": "^29.7.0",
@@ -85,17 +85,19 @@
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^11.0.0",
"del": "^7.0.0",
"eslint": "^7.32.0",
"eslint-config-kentcdodds": "^19.2.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest-dom": "^4.0.3",
"eslint-plugin-prettier": "^4.2.1",
"eslint": "^8.57.0",
"eslint-config-kentcdodds": "^21.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest-dom": "^5.4.0",
"eslint-plugin-kentcdodds": "^1.0.3",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react": "^7.32.0",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-sort-keys-fix": "^1.1.2",
"eslint-plugin-testing-library": "^5.9.1",
"eslint-plugin-typescript-sort-keys": "^2.1.0",
"eslint-plugin-typescript-sort-keys": "^3.2.0",
"husky": "^4.3.7",
"jest": "^29.3.1",
"jest-cli": "^29.3.1",
@@ -118,7 +120,7 @@
"ts-jest": "^29.2.5",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typescript": "^5.5.4",
"typescript": "~5.5.4",
"wait-on": "^8.0.0",
"web-ext": "^8.2.0",
"webpack": "^5.94.0",

View File

@@ -1,4 +1,4 @@
import '@testing-library/jest-dom/extend-expect';
import '@testing-library/jest-dom';
import chrome from 'sinon-chrome';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View File

@@ -1,11 +1,12 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import React from 'react';
import Alert from './Alert';
describe('Alert Component', () => {
it('should render with proper text on success type', () => {
const text = 'Test Text';
const { container } = render(<Alert text={text} type="success" />);
// eslint-disable-next-line testing-library/prefer-implicit-assert
expect(screen.getByText(text)).toBeInTheDocument();
expect(container).toMatchInlineSnapshot(`
<div>
@@ -20,6 +21,7 @@ describe('Alert Component', () => {
it('should render wtih proper text on danger type', () => {
const text = 'Test Text';
const { container } = render(<Alert text={text} type="danger" />);
// eslint-disable-next-line testing-library/prefer-implicit-assert
expect(screen.getByText(text)).toBeInTheDocument();
expect(container).toMatchInlineSnapshot(`
<div>

View File

@@ -1,5 +1,5 @@
import React, { MouseEventHandler, CSSProperties } from 'react';
import classNames from 'classnames';
import React, { CSSProperties, MouseEventHandler } from 'react';
import { SuccessOrFailType } from '../config/config';
interface AlertProps {
onClick?: MouseEventHandler<HTMLDivElement>;

View File

@@ -52,7 +52,7 @@ export default function CustomProjectNameList({
{label}
</label>
{sites.length > 0 && (
{sites.length > 0 ? (
<div className="d-flex flex-column gap-2">
{sites.map((site, i) => (
<div key={i} className="d-flex gap-2">
@@ -77,15 +77,15 @@ export default function CustomProjectNameList({
className="btn btn-sm btn-default"
onClick={() => handleRemoveSite(i)}
>
<i className="fa fa-fw fa-times"></i>
<i className="fa fa-fw fa-times" />
</button>
</div>
))}
</div>
)}
) : null}
<button type="button" onClick={handleAddNewSite} className="btn btn-default col-12">
<i className="fa fa-fw fa-plus me-2"></i>
<i className="fa fa-fw fa-plus me-2" />
Add Project Name
</button>
</div>

View File

@@ -2,7 +2,7 @@ import React from 'react';
import { renderWithProviders } from '../utils/test-utils';
import MainList from './MainList';
jest.mock('webextension-polyfill', () => {
jest.mock<typeof import('webextension-polyfill')>('webextension-polyfill', () => {
return {
runtime: {
getManifest: () => {
@@ -13,8 +13,7 @@ jest.mock('webextension-polyfill', () => {
});
describe('MainList', () => {
let loggingEnabled: boolean;
let totalTimeLoggedToday: string;
let loggingEnabled: boolean, totalTimeLoggedToday: string;
beforeEach(() => {
loggingEnabled = false;
totalTimeLoggedToday = '1/1/1999';

View File

@@ -45,7 +45,7 @@ export default function MainList({
return (
<div>
{user && (
{user ? (
<div className="row">
<div className="col-xs-12">
<blockquote>
@@ -56,8 +56,8 @@ export default function MainList({
</blockquote>
</div>
</div>
)}
{loggingEnabled && user && (
) : null}
{loggingEnabled && user ? (
<div className="row">
<div className="col-xs-12">
<p>
@@ -71,8 +71,8 @@ export default function MainList({
</p>
</div>
</div>
)}
{!loggingEnabled && user && (
) : null}
{!loggingEnabled && user ? (
<div className="row">
<div className="col-xs-12">
<p>
@@ -86,28 +86,28 @@ export default function MainList({
</p>
</div>
</div>
)}
) : null}
<div className="list-group">
<a href="#" className="list-group-item text-body-secondary" onClick={openOptionsPage}>
<i className="fa fa-fw fa-cogs me-2"></i>
<i className="fa fa-fw fa-cogs me-2" />
Options
</a>
{user && (
{user ? (
<div>
<a href="#" className="list-group-item text-body-secondary" onClick={logoutUser}>
<i className="fa fa-fw fa-sign-out me-2"></i>
<i className="fa fa-fw fa-sign-out me-2" />
Logout
</a>
</div>
)}
{!user && (
) : null}
{user ? null : (
<a
target="_blank"
rel="noreferrer"
href="https://wakatime.com/login"
className="list-group-item text-body-secondary"
>
<i className="fa fa-fw fa-sign-in me-2"></i>
<i className="fa fa-fw fa-sign-in me-2" />
Login
</a>
)}

View File

@@ -2,7 +2,7 @@ import React from 'react';
import { renderWithProviders } from '../utils/test-utils';
import NavBar from './NavBar';
jest.mock('webextension-polyfill', () => {
jest.mock<typeof import('webextension-polyfill')>('webextension-polyfill', () => {
return {
runtime: {
getManifest: () => {

View File

@@ -30,7 +30,7 @@ export default function NavBar(): JSX.Element {
rel="noreferrer"
className="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
>
<i className="fa fa-fw fa-filter me-2"></i>
<i className="fa fa-fw fa-filter me-2" />
Custom Rules
</a>
</li>
@@ -50,7 +50,7 @@ export default function NavBar(): JSX.Element {
rel="noreferrer"
className="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
>
<i className="fa fa-fw fa-tachometer me-2"></i>
<i className="fa fa-fw fa-tachometer me-2" />
Dashboard
</a>
</li>
@@ -77,7 +77,7 @@ export default function NavBar(): JSX.Element {
aria-label="Toggle navigation"
>
<span className="sr-only">Toggle navigation</span>
<i className="fa fa-fw fa-cogs"></i>
<i className="fa fa-fw fa-cogs" />
</button>
</div>
@@ -94,9 +94,9 @@ export default function NavBar(): JSX.Element {
role="button"
aria-expanded="false"
>
<i className="fa fa-fw fa-info me-2"></i>
<i className="fa fa-fw fa-info me-2" />
About
<span className="caret"></span>
<span className="caret" />
</a>
<ul className="dropdown-menu shadow-none ms-4" role="menu">
<li className="mb-2">
@@ -106,7 +106,7 @@ export default function NavBar(): JSX.Element {
rel="noreferrer"
className="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
>
<i className="fa fa-fw fa-bug me-2"></i>
<i className="fa fa-fw fa-bug me-2" />
Report an Issue
</a>
</li>
@@ -117,7 +117,7 @@ export default function NavBar(): JSX.Element {
rel="noreferrer"
className="text-body-secondary link-underline link-underline-opacity-0 d-flex w-100 align-items-center"
>
<i className="fa fa-fw fa-github me-2"></i>
<i className="fa fa-fw fa-github me-2" />
View on GitHub
</a>
</li>

View File

@@ -301,7 +301,7 @@ export default function Options(): JSX.Element {
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
/>
</div>
<div className="modal-body">
<SitesList

View File

@@ -40,7 +40,7 @@ export default function SitesList({
{label}
</label>
{sites.length > 0 && (
{sites.length > 0 ? (
<div className="d-flex flex-column gap-2">
{sites.map((site, i) => (
<div key={i} className="d-flex gap-2">
@@ -57,15 +57,15 @@ export default function SitesList({
className="btn btn-sm btn-default"
onClick={() => handleRemoveSite(i)}
>
<i className="fa fa-fw fa-times"></i>
<i className="fa fa-fw fa-times" />
</button>
</div>
))}
</div>
)}
) : null}
<button type="button" onClick={handleAddNewSite} className="btn btn-default col-12">
<i className="fa fa-fw fa-plus me-2"></i>
<i className="fa fa-fw fa-plus me-2" />
Add Site
</button>
<span className="text-secondary">{helpText}</span>

View File

@@ -38,18 +38,18 @@ export default function WakaTime(): JSX.Element {
return (
<div className="py-4 px-2 pt-0">
<NavBar />
{isApiKeyValid && extensionStatus === 'notSignedIn' && (
{isApiKeyValid && extensionStatus === 'notSignedIn' ? (
<Alert
type={config.alert.failure.type}
text={'Invalid API key or API url'}
text="Invalid API key or API url"
onClick={() => browser.runtime.openOptionsPage()}
style={{ cursor: 'pointer' }}
/>
)}
{!isApiKeyValid && (
) : null}
{isApiKeyValid ? null : (
<Alert
type={config.alert.failure.type}
text={'Please update your api key'}
text="Please update your api key"
onClick={() => browser.runtime.openOptionsPage()}
style={{ cursor: 'pointer' }}
/>

View File

@@ -1,6 +1,6 @@
import config from './config';
jest.mock('webextension-polyfill', () => {
jest.mock<typeof import('webextension-polyfill')>('webextension-polyfill', () => {
return {
runtime: {
getManifest: () => {

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />

View File

@@ -1,3 +1,3 @@
<!DOCTYPE html>
<!doctype html>
<script src="public/js/browser-polyfill.min.js"></script>
<script src="devtools.js"></script>

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />

View File

@@ -50,9 +50,9 @@ export async function changeExtensionIcon(color?: ColorIconTypes): Promise<void>
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (IS_FIREFOX && browser.browserAction) {
await browser.browserAction.setIcon({ path: path }); // Support for FF with manifest V2
await browser.browserAction.setIcon({ path }); // Support for FF with manifest V2
} else if ((browser.action as browser.Action.Static | undefined) !== undefined) {
await browser.action.setIcon({ path: path }); // Support for Chrome with manifest V3
await browser.action.setIcon({ path }); // Support for Chrome with manifest V3
}
}

View File

@@ -4,7 +4,7 @@
export default function getDomainFromUrl(url: string): string {
const parts = url.split('/');
return parts[0] + '//' + parts[2];
return `${parts[0]}//${parts[2]}`;
}
/**

View File

@@ -1,10 +1,10 @@
export const IS_EDGE = navigator.userAgent.includes('Edg');
export const IS_FIREFOX = navigator.userAgent.includes('Firefox');
export const IS_CHROME = IS_EDGE === false && IS_FIREFOX === false;
export const IS_CHROME = !IS_EDGE && !IS_FIREFOX;
export const getOperatingSystem = (): Promise<string> => {
return new Promise((resolve) => {
chrome.runtime.getPlatformInfo(function (info) {
chrome.runtime.getPlatformInfo((info) => {
resolve(`${info.os}_${info.arch}`);
});
});

View File

@@ -202,7 +202,7 @@ const Canva: HeartbeatParser = (_url: string): OptionalHeartbeat | undefined =>
// make sure the page title matches the design input element's value, meaning this is a design file
const canvaProjectInput = Array.from(
document.querySelector('nav')?.querySelectorAll('input')?.values() ?? [],
document.querySelector('nav')?.querySelectorAll('input').values() ?? [],
).find((inp) => inp.value === projectName);
if (!canvaProjectInput) return;

View File

@@ -1,7 +1,5 @@
import type { PreloadedState } from '@reduxjs/toolkit';
import { combineReducers, configureStore, Store } from '@reduxjs/toolkit';
import type { RenderOptions } from '@testing-library/react';
import { render } from '@testing-library/react';
import { render, type RenderOptions } from '@testing-library/react';
import React, { PropsWithChildren } from 'react';
import { Provider } from 'react-redux';
import { RootState } from '../stores/createStore';
@@ -13,7 +11,9 @@ import userReducer, { initialState as InitalCurrentUser } from '../reducers/curr
// This type interface extends the default options for render from RTL, as well
// as allows the user to specify other things such as initialState, store.
interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {
preloadedState?: PreloadedState<RootState>;
// TODO: Fix Type as `PreloadedState` is not exported in the latest version of `@redux/toolkit`
// preloadedState?: PreloadedState<RootState>;
preloadedState?: object;
store?: Store<RootState>;
}

View File

@@ -12,8 +12,7 @@ const fiveMinutes = 300000;
* @returns {() => void} The debounced function.
*/
function debounce(func: () => void, timeout = oneMinute, maxWaitTime = fiveMinutes) {
let timer: NodeJS.Timeout | undefined;
let lastExecutionTime: number | undefined;
let timer: NodeJS.Timeout | undefined, lastExecutionTime: number | undefined;
return (...args: unknown[]) => {
clearTimeout(timer);
if (lastExecutionTime && lastExecutionTime + maxWaitTime < Date.now()) {
@@ -28,7 +27,7 @@ function debounce(func: () => void, timeout = oneMinute, maxWaitTime = fiveMinut
}
const sendHeartbeat = debounce(async () => {
chrome.runtime.sendMessage({ task: 'handleActivity' });
void chrome.runtime.sendMessage({ task: 'handleActivity' });
});
chrome.runtime.onMessage.addListener(

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />

View File

@@ -56,12 +56,12 @@ const getConfigByBrowser = (isProd: boolean, browser: BrowserTypes): webpack.Con
],
}),
new webpack.DefinePlugin({
['process.env.API_URL']: JSON.stringify('https://api.wakatime.com/api/v1'),
['process.env.CURRENT_USER_API_URL']: JSON.stringify('/users/current'),
['process.env.HEARTBEAT_API_URL']: JSON.stringify('/users/current/heartbeats.bulk'),
['process.env.LOGOUT_USER_URL']: JSON.stringify('https://wakatime.com/logout'),
['process.env.NODE_ENV']: JSON.stringify(isProd ? 'production' : 'development'),
['process.env.SUMMARIES_API_URL']: JSON.stringify('/users/current/summaries'),
'process.env.API_URL': JSON.stringify('https://api.wakatime.com/api/v1'),
'process.env.CURRENT_USER_API_URL': JSON.stringify('/users/current'),
'process.env.HEARTBEAT_API_URL': JSON.stringify('/users/current/heartbeats.bulk'),
'process.env.LOGOUT_USER_URL': JSON.stringify('https://wakatime.com/logout'),
'process.env.NODE_ENV': JSON.stringify(isProd ? 'production' : 'development'),
'process.env.SUMMARIES_API_URL': JSON.stringify('/users/current/summaries'),
}),
],
resolve: {