Update typescript and eslint config (#1878)

* Update eslint rules
* Update typescript to 4.4
* Disable react/display-name
* Add @typescript-eslint/typescript-estree
This commit is contained in:
InfiniteTF
2021-10-28 01:27:26 +02:00
committed by GitHub
parent 372ea7218e
commit c93b5e12b7
30 changed files with 1815 additions and 982 deletions

View File

@@ -10,18 +10,23 @@
"project": "./tsconfig.json" "project": "./tsconfig.json"
}, },
"plugins": [ "plugins": [
"@typescript-eslint" "@typescript-eslint",
"jsx-a11y"
], ],
"extends": [ "extends": [
"airbnb-typescript", "airbnb-typescript",
"airbnb/hooks", "airbnb/hooks",
"plugin:react/recommended",
"plugin:import/recommended",
"prettier", "prettier",
"prettier/prettier", "prettier/prettier"
"prettier/react",
"prettier/@typescript-eslint"
], ],
"settings": {
"react": {
"version": "detect"
}
},
"rules": { "rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": 2, "@typescript-eslint/no-explicit-any": 2,
"@typescript-eslint/naming-convention": [ "@typescript-eslint/naming-convention": [
"error", "error",
@@ -48,36 +53,17 @@
], ],
"import/named": "off", "import/named": "off",
"import/namespace": "off", "import/namespace": "off",
"import/default": "off",
"import/no-named-as-default-member": "off",
"import/no-named-as-default": "off",
"import/no-cycle": "off",
"import/no-unused-modules": "off",
"import/no-deprecated": "off",
"import/no-unresolved": "off", "import/no-unresolved": "off",
"import/prefer-default-export": "off", "react/display-name": "off",
"import/no-extraneous-dependencies": "off",
"indent": "off",
"@typescript-eslint/indent": "off",
"react/prop-types": "off", "react/prop-types": "off",
"react/destructuring-assignment": "off",
"react/require-default-props": "off",
"react/jsx-props-no-spreading": "off",
"react/sort-comp": "off",
"react/style-prop-object": ["error", { "react/style-prop-object": ["error", {
"allow": ["FormattedNumber"] "allow": ["FormattedNumber"]
}], }],
"spaced-comment": ["error", "always", { "spaced-comment": ["error", "always", {
"markers": ["/"] "markers": ["/"]
}], }],
"max-classes-per-file": "off",
"no-plusplus": "off",
"prefer-destructuring": ["error", {"object": true, "array": false}], "prefer-destructuring": ["error", {"object": true, "array": false}],
"default-case": "off",
"consistent-return": "off",
"@typescript-eslint/no-use-before-define": ["error", { "functions": false, "classes": true }], "@typescript-eslint/no-use-before-define": ["error", { "functions": false, "classes": true }],
"no-underscore-dangle": "off", "no-nested-ternary": "off"
"no-nested-ternary": "off",
"jsx-a11y/media-has-caption": "off"
} }
} }

View File

@@ -55,9 +55,9 @@
"mousetrap": "^1.6.5", "mousetrap": "^1.6.5",
"mousetrap-pause": "^1.0.0", "mousetrap-pause": "^1.0.0",
"query-string": "6.13.8", "query-string": "6.13.8",
"react": "17.0.1", "react": "17.0.2",
"react-bootstrap": "1.4.3", "react-bootstrap": "1.4.3",
"react-dom": "17.0.1", "react-dom": "17.0.2",
"react-helmet": "^6.1.0", "react-helmet": "^6.1.0",
"react-intl": "^5.10.16", "react-intl": "^5.10.16",
"react-jw-player": "1.19.1", "react-jw-player": "1.19.1",
@@ -88,21 +88,22 @@
"@types/lodash": "^4.14.168", "@types/lodash": "^4.14.168",
"@types/mousetrap": "^1.6.5", "@types/mousetrap": "^1.6.5",
"@types/node": "14.14.22", "@types/node": "14.14.22",
"@types/react": "17.0.0", "@types/react": "17.0.31",
"@types/react-dom": "^17.0.0", "@types/react-dom": "^17.0.10",
"@types/react-helmet": "^6.1.3", "@types/react-helmet": "^6.1.3",
"@types/react-router-bootstrap": "^0.24.5", "@types/react-router-bootstrap": "^0.24.5",
"@types/react-router-dom": "5.1.7", "@types/react-router-dom": "5.1.7",
"@types/react-router-hash-link": "^1.2.1", "@types/react-router-hash-link": "^1.2.1",
"@typescript-eslint/eslint-plugin": "^4.14.0", "@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.14.0", "@typescript-eslint/parser": "^4.33.0",
"craco-esbuild": "^0.4.2", "craco-esbuild": "^0.4.2",
"eslint": "^7.18.0", "eslint": "^7.32.0",
"eslint-config-airbnb-typescript": "^12.0.0", "eslint-config-airbnb": "^18.2.1",
"eslint-config-prettier": "^7.2.0", "eslint-config-airbnb-typescript": "^14.0.1",
"eslint-plugin-import": "^2.22.1", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.22.0", "eslint-plugin-react": "^7.26.1",
"eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-react-hooks": "^4.2.0",
"extract-react-intl-messages": "^4.1.1", "extract-react-intl-messages": "^4.1.1",
"postcss-safe-parser": "^5.0.2", "postcss-safe-parser": "^5.0.2",
@@ -111,6 +112,6 @@
"stylelint": "^13.9.0", "stylelint": "^13.9.0",
"stylelint-config-prettier": "^8.0.2", "stylelint-config-prettier": "^8.0.2",
"stylelint-order": "^4.1.0", "stylelint-order": "^4.1.0",
"typescript": "~4.0.5" "typescript": "~4.4.4"
} }
} }

View File

@@ -1,6 +1,6 @@
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { Route, Switch, useRouteMatch } from "react-router-dom"; import { Route, Switch, useRouteMatch } from "react-router-dom";
import { IntlProvider } from "react-intl"; import { IntlProvider, CustomFormats } from "react-intl";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
import { mergeWith } from "lodash"; import { mergeWith } from "lodash";
import { ToastProvider } from "src/hooks/Toast"; import { ToastProvider } from "src/hooks/Toast";
@@ -32,7 +32,7 @@ import { Setup } from "./components/Setup/Setup";
import { Migrate } from "./components/Setup/Migrate"; import { Migrate } from "./components/Setup/Migrate";
import * as GQL from "./core/generated-graphql"; import * as GQL from "./core/generated-graphql";
import { LoadingIndicator, TITLE_SUFFIX } from "./components/Shared"; import { LoadingIndicator, TITLE_SUFFIX } from "./components/Shared";
import ConfigurationProvider from "./hooks/Config"; import { ConfigurationProvider } from "./hooks/Config";
initPolyfills(); initPolyfills();
@@ -41,7 +41,7 @@ MousetrapPause(Mousetrap);
// Set fontawesome/free-solid-svg as default fontawesome icons // Set fontawesome/free-solid-svg as default fontawesome icons
library.add(fas); library.add(fas);
const intlFormats = { const intlFormats: CustomFormats = {
date: { date: {
long: { year: "numeric", month: "long", day: "numeric" }, long: { year: "numeric", month: "long", day: "numeric" },
}, },

View File

@@ -1,6 +1,6 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { useHistory } from "react-router-dom"; import { useHistory, Prompt } from "react-router-dom";
import { import {
Button, Button,
Dropdown, Dropdown,
@@ -30,7 +30,6 @@ import {
} from "src/components/Shared"; } from "src/components/Shared";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { useFormik } from "formik"; import { useFormik } from "formik";
import { Prompt } from "react-router";
import { FormUtils, TextUtils } from "src/utils"; import { FormUtils, TextUtils } from "src/utils";
import { RatingStars } from "src/components/Scenes/SceneDetails/RatingStars"; import { RatingStars } from "src/components/Scenes/SceneDetails/RatingStars";
import { GalleryScrapeDialog } from "./GalleryScrapeDialog"; import { GalleryScrapeDialog } from "./GalleryScrapeDialog";

View File

@@ -11,7 +11,7 @@ export const GalleryScenesPanel: React.FC<IGalleryScenesPanelProps> = ({
}) => ( }) => (
<div className="container gallery-scenes"> <div className="container gallery-scenes">
{scenes.map((scene) => ( {scenes.map((scene) => (
<SceneCard scene={scene} /> <SceneCard scene={scene} key={scene.id} />
))} ))}
</div> </div>
); );

View File

@@ -14,7 +14,7 @@ import {
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { FormUtils } from "src/utils"; import { FormUtils } from "src/utils";
import { useFormik } from "formik"; import { useFormik } from "formik";
import { Prompt } from "react-router"; import { Prompt } from "react-router-dom";
import { RatingStars } from "src/components/Scenes/SceneDetails/RatingStars"; import { RatingStars } from "src/components/Scenes/SceneDetails/RatingStars";
interface IProps { interface IProps {

View File

@@ -162,7 +162,7 @@ export const ListFilter: React.FC<IListFilterProps> = ({
const SavedFilterDropdown = React.forwardRef< const SavedFilterDropdown = React.forwardRef<
HTMLDivElement, HTMLDivElement,
HTMLAttributes<HTMLDivElement> HTMLAttributes<HTMLDivElement>
>(({ style, className }, ref) => ( >(({ style, className }: HTMLAttributes<HTMLDivElement>, ref) => (
<div ref={ref} style={style} className={className}> <div ref={ref} style={style} className={className}>
<SavedFilterList <SavedFilterList
filter={filter} filter={filter}
@@ -173,6 +173,7 @@ export const ListFilter: React.FC<IListFilterProps> = ({
/> />
</div> </div>
)); ));
SavedFilterDropdown.displayName = "SavedFilterDropdown";
function render() { function render() {
const currentSortBy = filterOptions.sortByOptions.find( const currentSortBy = filterOptions.sortByOptions.find(

View File

@@ -100,6 +100,7 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
return ( return (
<OverlayTrigger <OverlayTrigger
overlay={<Tooltip id="edit">{button.text}</Tooltip>} overlay={<Tooltip id="edit">{button.text}</Tooltip>}
key={button.text}
> >
<Button <Button
variant={button.buttonVariant ?? "secondary"} variant={button.buttonVariant ?? "secondary"}

View File

@@ -6,7 +6,7 @@ import { LoadingIndicator } from "src/components/Shared";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { MovieEditPanel } from "./MovieEditPanel"; import { MovieEditPanel } from "./MovieEditPanel";
export const MovieCreate: React.FC = () => { const MovieCreate: React.FC = () => {
const history = useHistory(); const history = useHistory();
const Toast = useToast(); const Toast = useToast();

View File

@@ -33,7 +33,7 @@ import { useToast } from "src/hooks";
import { ImageUtils, FormUtils, TextUtils, getStashIDs } from "src/utils"; import { ImageUtils, FormUtils, TextUtils, getStashIDs } from "src/utils";
import { MovieSelect } from "src/components/Shared/Select"; import { MovieSelect } from "src/components/Shared/Select";
import { useFormik } from "formik"; import { useFormik } from "formik";
import { Prompt } from "react-router"; import { Prompt } from "react-router-dom";
import { ConfigurationContext } from "src/hooks/Config"; import { ConfigurationContext } from "src/hooks/Config";
import { stashboxDisplayName } from "src/utils/stashbox"; import { stashboxDisplayName } from "src/utils/stashbox";
import { SceneMovieTable } from "./SceneMovieTable"; import { SceneMovieTable } from "./SceneMovieTable";

View File

@@ -25,7 +25,11 @@ const SceneSearchResultDetails: React.FC<ISceneSearchResultDetailsProps> = ({
<Row> <Row>
<Col> <Col>
{scene.performers?.map((performer) => ( {scene.performers?.map((performer) => (
<Badge className="tag-item" variant="secondary"> <Badge
className="tag-item"
variant="secondary"
key={performer.name}
>
{performer.name} {performer.name}
</Badge> </Badge>
))} ))}
@@ -41,7 +45,11 @@ const SceneSearchResultDetails: React.FC<ISceneSearchResultDetailsProps> = ({
<Row> <Row>
<Col> <Col>
{scene.tags?.map((tag) => ( {scene.tags?.map((tag) => (
<Badge className="tag-item" variant="secondary"> <Badge
className="tag-item"
variant="secondary"
key={tag.stored_id}
>
{tag.name} {tag.name}
</Badge> </Badge>
))} ))}
@@ -136,7 +144,7 @@ export const SceneQueryModal: React.FC<IProps> = ({
const r = await queryScrapeSceneQuery(scraper, input); const r = await queryScrapeSceneQuery(scraper, input);
setScenes(r.data.scrapeSingleScene); setScenes(r.data.scrapeSingleScene);
} catch (err) { } catch (err) {
setError(err); if (err instanceof Error) setError(err);
} finally { } finally {
setLoading(false); setLoading(false);
} }

View File

@@ -9,7 +9,8 @@ import {
} from "src/core/StashService"; } from "src/core/StashService";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { Icon, LoadingIndicator } from "src/components/Shared"; import { Icon, LoadingIndicator } from "src/components/Shared";
import StashBoxConfiguration, { import {
StashBoxConfiguration,
IStashBoxInstance, IStashBoxInstance,
} from "./StashBoxConfiguration"; } from "./StashBoxConfiguration";
import StashConfiguration from "./StashConfiguration"; import StashConfiguration from "./StashConfiguration";
@@ -47,7 +48,7 @@ export const ExclusionPatterns: React.FC<IExclusionPatternsProps> = (props) => {
<Form.Group> <Form.Group>
{props.excludes && {props.excludes &&
props.excludes.map((regexp, i) => ( props.excludes.map((regexp, i) => (
<InputGroup> <InputGroup key={regexp}>
<Form.Control <Form.Control
className="col col-sm-6 text-input" className="col col-sm-6 text-input"
value={regexp} value={regexp}

View File

@@ -1,7 +1,7 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Formik, useFormikContext } from "formik"; import { Formik, useFormikContext } from "formik";
import { Button, Form } from "react-bootstrap"; import { Button, Form } from "react-bootstrap";
import { Prompt } from "react-router"; import { Prompt } from "react-router-dom";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import * as yup from "yup"; import * as yup from "yup";
import { import {

View File

@@ -72,7 +72,7 @@ export const SettingsPluginsPanel: React.FC = () => {
> >
<ul> <ul>
{h.hooks?.map((hh) => ( {h.hooks?.map((hh) => (
<li> <li key={hh}>
<code>{hh}</code> <code>{hh}</code>
</li> </li>
))} ))}

View File

@@ -50,7 +50,7 @@ export const DirectorySelectionDialog: React.FC<IDirectorySelectionDialogProps>
> >
<div className="dialog-container"> <div className="dialog-container">
{paths.map((p) => ( {paths.map((p) => (
<Row className="align-items-center mb-1"> <Row className="align-items-center mb-1" key={p}>
<Form.Label column xs={10}> <Form.Label column xs={10}>
{p} {p}
</Form.Label> </Form.Label>

View File

@@ -140,5 +140,3 @@ export const StashBoxConfiguration: React.FC<IStashBoxConfigurationProps> = ({
</Form.Group> </Form.Group>
); );
}; };
export default StashBoxConfiguration;

View File

@@ -64,7 +64,7 @@ interface IStashConfigurationProps {
setStashes: (v: GQL.StashConfig[]) => void; setStashes: (v: GQL.StashConfig[]) => void;
} }
export const StashConfiguration: React.FC<IStashConfigurationProps> = ({ const StashConfiguration: React.FC<IStashConfigurationProps> = ({
stashes, stashes,
setStashes, setStashes,
}) => { }) => {

View File

@@ -80,7 +80,7 @@ export const Migrate: React.FC = () => {
const newURL = new URL("/", window.location.toString()); const newURL = new URL("/", window.location.toString());
window.location.href = newURL.toString(); window.location.href = newURL.toString();
} catch (e) { } catch (e) {
setMigrateError(e.message ?? e.toString()); if (e instanceof Error) setMigrateError(e.message ?? e.toString());
setMigrateLoading(false); setMigrateLoading(false);
} }
} }

View File

@@ -310,7 +310,7 @@ export const Setup: React.FC = () => {
return ( return (
<ul> <ul>
{stashes.map((s) => ( {stashes.map((s) => (
<li> <li key={s.path}>
<code>{s.path} </code> <code>{s.path} </code>
{maybeRenderExclusions(s)} {maybeRenderExclusions(s)}
</li> </li>
@@ -329,7 +329,7 @@ export const Setup: React.FC = () => {
stashes, stashes,
}); });
} catch (e) { } catch (e) {
setSetupError(e.message ?? e.toString()); if (e instanceof Error) setSetupError(e.message ?? e.toString());
} finally { } finally {
setLoading(false); setLoading(false);
next(); next();

View File

@@ -104,7 +104,7 @@ const DeleteEntityDialog: React.FC<IDeleteEntityDialogProps> = ({
</p> </p>
<ul> <ul>
{selected.slice(0, 10).map((s) => ( {selected.slice(0, 10).map((s) => (
<li>{s.name}</li> <li key={s.name}>{s.name}</li>
))} ))}
{selected.length > 10 && ( {selected.length > 10 && (
<FormattedMessage <FormattedMessage

View File

@@ -42,7 +42,7 @@ export const StudioDetailsPanel: React.FC<IStudioDetailsPanel> = ({
</dt> </dt>
<dd> <dd>
{studio.aliases.map((a) => ( {studio.aliases.map((a) => (
<Badge className="tag-item" variant="secondary"> <Badge className="tag-item" variant="secondary" key={a}>
{a} {a}
</Badge> </Badge>
))} ))}

View File

@@ -46,7 +46,7 @@ const Config: React.FC<IConfigProps> = ({ show, config, setConfig }) => {
<span> <span>
{excludedFields.length > 0 {excludedFields.length > 0
? excludedFields.map((f) => ( ? excludedFields.map((f) => (
<Badge variant="secondary" className="tag-item"> <Badge variant="secondary" className="tag-item" key={f}>
{TextUtils.capitalize(f)} {TextUtils.capitalize(f)}
</Badge> </Badge>
)) ))

View File

@@ -271,7 +271,7 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
-1; -1;
return ( return (
<div> <div key={performer.id}>
<InputGroup className="PerformerTagger-box-link"> <InputGroup className="PerformerTagger-box-link">
<InputGroup.Text>{link}</InputGroup.Text> <InputGroup.Text>{link}</InputGroup.Text>
<InputGroup.Append> <InputGroup.Append>

View File

@@ -89,7 +89,7 @@ const getFingerprintStatus = (
const phashList = ( const phashList = (
<div className="m-2"> <div className="m-2">
{phashMatches.map((fp) => ( {phashMatches.map((fp) => (
<div> <div key={fp.hash}>
<b>{fp.hash}</b> <b>{fp.hash}</b>
{fp.hash === stashScene.phash {fp.hash === stashScene.phash
? ", Exact match" ? ", Exact match"

View File

@@ -21,7 +21,7 @@ export const TagDetailsPanel: React.FC<ITagDetails> = ({ tag }) => {
</dt> </dt>
<dd className="col-9 col-xl-10"> <dd className="col-9 col-xl-10">
{tag.aliases.map((a) => ( {tag.aliases.map((a) => (
<Badge className="tag-item" variant="secondary"> <Badge className="tag-item" variant="secondary" key={a}>
{a} {a}
</Badge> </Badge>
))} ))}

View File

@@ -6,7 +6,7 @@ import { FormUtils } from "src/utils";
import { useTagsMerge } from "src/core/StashService"; import { useTagsMerge } from "src/core/StashService";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { useHistory } from "react-router"; import { useHistory } from "react-router-dom";
interface ITagMergeModalProps { interface ITagMergeModalProps {
show: boolean; show: boolean;

View File

@@ -24,5 +24,3 @@ export const ConfigurationProvider: React.FC<IContext> = ({
</ConfigurationContext.Provider> </ConfigurationContext.Provider>
); );
}; };
export default ConfigurationProvider;

View File

@@ -27,7 +27,7 @@ export function useLocalForage<T>(
key: string, key: string,
defaultValue: T = {} as T defaultValue: T = {} as T
): [ILocalForage<T>, Dispatch<SetStateAction<T>>] { ): [ILocalForage<T>, Dispatch<SetStateAction<T>>] {
const [error, setError] = React.useState(null); const [error, setError] = React.useState<Error | null>(null);
const [data, setData] = React.useState<T>(Cache[key] as T); const [data, setData] = React.useState<T>(Cache[key] as T);
const [loading, setLoading] = React.useState(Loading[key]); const [loading, setLoading] = React.useState(Loading[key]);
@@ -45,7 +45,7 @@ export function useLocalForage<T>(
} }
setError(null); setError(null);
} catch (err) { } catch (err) {
setError(err); if (err instanceof Error) setError(err);
Cache[key] = defaultValue; Cache[key] = defaultValue;
} finally { } finally {
Loading[key] = false; Loading[key] = false;

View File

@@ -18,7 +18,7 @@
"moduleResolution": "node", "moduleResolution": "node",
"resolveJsonModule": true, "resolveJsonModule": true,
"noEmit": true, "noEmit": true,
"jsx": "react", "jsx": "react-jsx",
"downlevelIteration": true, "downlevelIteration": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"baseUrl": ".", "baseUrl": ".",

File diff suppressed because it is too large Load Diff