diff --git a/.eslintrc.js b/.eslintrc.js index 01714c04c4..03e06eb499 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,8 +2,9 @@ const restrictedGlobals = require('confusing-browser-globals'); module.exports = { root: true, + parser: '@typescript-eslint/parser', plugins: [ - '@babel', + '@typescript-eslint', 'react', 'promise', 'import', @@ -16,14 +17,6 @@ module.exports = { es2017: true, es2020: true }, - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - ecmaFeatures: { - impliedStrict: true, - jsx: true - } - }, extends: [ 'eslint:recommended', 'plugin:react/recommended', @@ -53,14 +46,19 @@ module.exports = { 'no-multi-spaces': ['error'], 'no-multiple-empty-lines': ['error', { 'max': 1 }], 'no-nested-ternary': ['error'], + 'no-redeclare': ['off'], + '@typescript-eslint/no-redeclare': ['error', { builtinGlobals: false }], 'no-restricted-globals': ['error'].concat(restrictedGlobals), 'no-return-assign': ['error'], 'no-return-await': ['error'], 'no-sequences': ['error', { 'allowInParentheses': false }], - 'no-shadow': ['error'], + 'no-shadow': ['off'], + '@typescript-eslint/no-shadow': ['error'], 'no-trailing-spaces': ['error'], - '@babel/no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }], - 'no-useless-constructor': ['error'], + 'no-unused-expressions': ['off'], + '@typescript-eslint/no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }], + 'no-useless-constructor': ['off'], + '@typescript-eslint/no-useless-constructor': ['error'], 'no-var': ['error'], 'no-void': ['error', { 'allowAsStatement': true }], 'no-warning-comments': ['warn', { 'terms': ['fixme', 'hack', 'xxx'] }], @@ -71,7 +69,7 @@ module.exports = { 'prefer-const': ['error', { 'destructuring': 'all' }], 'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }], 'radix': ['error'], - '@babel/semi': ['error'], + '@typescript-eslint/semi': ['error'], 'space-before-blocks': ['error'], 'space-infix-ops': 'error', 'yoda': 'error', @@ -201,9 +199,9 @@ module.exports = { files: [ './src/**/*.js', './src/**/*.jsx', - './src/**/*.ts' + './src/**/*.ts', + './src/**/*.tsx' ], - parser: '@babel/eslint-parser', env: { node: false, amd: true, @@ -241,8 +239,6 @@ module.exports = { 'TaskButton': 'writable', 'UserParentalControlPage': 'writable', 'Windows': 'readonly' - }, - rules: { } }, // TypeScript source files @@ -251,8 +247,6 @@ module.exports = { './src/**/*.ts', './src/**/*.tsx' ], - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint'], extends: [ 'eslint:recommended', 'plugin:import/typescript', @@ -263,12 +257,6 @@ module.exports = { 'plugin:jsx-a11y/recommended' ], rules: { - // Use TypeScript equivalent rules when required - 'no-shadow': ['off'], - '@typescript-eslint/no-shadow': ['error'], - 'no-useless-constructor': ['off'], - '@typescript-eslint/no-useless-constructor': ['error'], - 'sonarjs/cognitive-complexity': ['warn'] } } diff --git a/package-lock.json b/package-lock.json index 6026fe142e..20807c8044 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,8 +56,6 @@ }, "devDependencies": { "@babel/core": "7.21.4", - "@babel/eslint-parser": "7.21.3", - "@babel/eslint-plugin": "7.19.1", "@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-proposal-private-methods": "7.18.6", "@babel/plugin-transform-modules-umd": "7.18.6", @@ -225,40 +223,6 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/eslint-parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz", - "integrity": "sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg==", - "dev": true, - "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@babel/eslint-plugin": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.19.1.tgz", - "integrity": "sha512-ElGPkQPapKMa3zVqXHkZYzuL7I5LbRw9UWBUArgWsdWDDb9XcACqOpBib5tRPA9XvbVZYrFUkoQPbiJ4BFvu4w==", - "dev": true, - "dependencies": { - "eslint-rule-composer": "^0.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/eslint-parser": ">=7.11.0", - "eslint": ">=7.5.0" - } - }, "node_modules/@babel/generator": { "version": "7.21.4", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", @@ -2902,15 +2866,6 @@ "node": ">=4" } }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, - "dependencies": { - "eslint-scope": "5.1.1" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -7232,15 +7187,6 @@ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -7254,15 +7200,6 @@ "node": ">=8.0.0" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -20171,26 +20108,6 @@ "semver": "^6.3.0" } }, - "@babel/eslint-parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz", - "integrity": "sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg==", - "dev": true, - "requires": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - } - }, - "@babel/eslint-plugin": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-plugin/-/eslint-plugin-7.19.1.tgz", - "integrity": "sha512-ElGPkQPapKMa3zVqXHkZYzuL7I5LbRw9UWBUArgWsdWDDb9XcACqOpBib5tRPA9XvbVZYrFUkoQPbiJ4BFvu4w==", - "dev": true, - "requires": { - "eslint-rule-composer": "^0.3.0" - } - }, "@babel/generator": { "version": "7.21.4", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", @@ -21938,15 +21855,6 @@ "glob-to-regexp": "^0.3.0" } }, - "@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, - "requires": { - "eslint-scope": "5.1.1" - } - }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -25452,12 +25360,6 @@ "dev": true, "requires": {} }, - "eslint-rule-composer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", - "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", - "dev": true - }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -25468,12 +25370,6 @@ "estraverse": "^4.1.1" } }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, "espree": { "version": "9.5.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", diff --git a/package.json b/package.json index 4e7e73d04c..5aca9baac6 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,6 @@ "license": "GPL-2.0-or-later", "devDependencies": { "@babel/core": "7.21.4", - "@babel/eslint-parser": "7.21.3", - "@babel/eslint-plugin": "7.19.1", "@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-proposal-private-methods": "7.18.6", "@babel/plugin-transform-modules-umd": "7.18.6", diff --git a/src/apiclient.d.ts b/src/apiclient.d.ts index 33f3752ca7..a9f7f61ccd 100644 --- a/src/apiclient.d.ts +++ b/src/apiclient.d.ts @@ -268,7 +268,7 @@ declare module 'jellyfin-apiclient' { sendWebSocketMessage(name: string, data: any): void; serverAddress(val?: string): string; serverId(): string; - serverVersion(): string + serverVersion(): string; setAuthenticationInfo(accessKey?: string, userId?: string): void; setRequestHeaders(headers: any): void; setSystemInfo(info: SystemInfo): void; diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index d4f3aafa49..0271a5084b 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -1118,7 +1118,6 @@ let refreshIndicatorLoaded; function importRefreshIndicator() { if (!refreshIndicatorLoaded) { refreshIndicatorLoaded = true; - /* eslint-disable-next-line @babel/no-unused-expressions */ import('../../elements/emby-itemrefreshindicator/emby-itemrefreshindicator'); } } @@ -1469,7 +1468,6 @@ function getHoverMenuHtml(item, action) { const userData = item.UserData || {}; if (itemHelper.canMarkPlayed(item)) { - /* eslint-disable-next-line @babel/no-unused-expressions */ import('../../elements/emby-playstatebutton/emby-playstatebutton'); html += ''; } @@ -1477,7 +1475,6 @@ function getHoverMenuHtml(item, action) { if (itemHelper.canRate(item)) { const likes = userData.Likes == null ? '' : userData.Likes; - /* eslint-disable-next-line @babel/no-unused-expressions */ import('../../elements/emby-ratingbutton/emby-ratingbutton'); html += ''; } diff --git a/src/components/dashboard/users/AccessContainer.tsx b/src/components/dashboard/users/AccessContainer.tsx index 32fe9c213d..88727f396a 100644 --- a/src/components/dashboard/users/AccessContainer.tsx +++ b/src/components/dashboard/users/AccessContainer.tsx @@ -12,7 +12,7 @@ type IProps = { listTitle?: string; description?: string; children?: React.ReactNode -} +}; const AccessContainer: FunctionComponent = ({ containerClassName, headerTitle, checkBoxClassName, checkBoxTitle, listContainerClassName, accessClassName, listTitle, description, children }: IProps) => { return ( diff --git a/src/components/dashboard/users/AccessScheduleList.tsx b/src/components/dashboard/users/AccessScheduleList.tsx index 41c55c3621..f1e5affb8c 100644 --- a/src/components/dashboard/users/AccessScheduleList.tsx +++ b/src/components/dashboard/users/AccessScheduleList.tsx @@ -9,7 +9,7 @@ type AccessScheduleListProps = { DayOfWeek?: string; StartHour?: number ; EndHour?: number; -} +}; function getDisplayTime(hours = 0) { let minutes = 0; diff --git a/src/components/dashboard/users/BlockedTagList.tsx b/src/components/dashboard/users/BlockedTagList.tsx index 20e7f88ef2..5158a63e97 100644 --- a/src/components/dashboard/users/BlockedTagList.tsx +++ b/src/components/dashboard/users/BlockedTagList.tsx @@ -3,7 +3,7 @@ import IconButtonElement from '../../../elements/IconButtonElement'; type IProps = { tag?: string; -} +}; const BlockedTagList: FunctionComponent = ({ tag }: IProps) => { return ( diff --git a/src/components/dashboard/users/LinkEditUserPreferences.tsx b/src/components/dashboard/users/LinkEditUserPreferences.tsx index fde63ba514..fd272fd770 100644 --- a/src/components/dashboard/users/LinkEditUserPreferences.tsx +++ b/src/components/dashboard/users/LinkEditUserPreferences.tsx @@ -4,7 +4,7 @@ import globalize from '../../../scripts/globalize'; type IProps = { title?: string; className?: string; -} +}; const createLinkElement = ({ className, title }: IProps) => ({ __html: ` ({ __html: ` { if (lastActivityDate) { diff --git a/src/components/dashboard/users/UserPasswordForm.tsx b/src/components/dashboard/users/UserPasswordForm.tsx index 8cfb47b5b1..0337c06510 100644 --- a/src/components/dashboard/users/UserPasswordForm.tsx +++ b/src/components/dashboard/users/UserPasswordForm.tsx @@ -11,7 +11,7 @@ import InputElement from '../../../elements/InputElement'; type IProps = { userId: string; -} +}; const UserPasswordForm: FunctionComponent = ({ userId }: IProps) => { const element = useRef(null); diff --git a/src/components/search/LiveTVSearchResults.tsx b/src/components/search/LiveTVSearchResults.tsx index 5b4c097c5c..a087dc23cc 100644 --- a/src/components/search/LiveTVSearchResults.tsx +++ b/src/components/search/LiveTVSearchResults.tsx @@ -24,7 +24,7 @@ type LiveTVSearchResultsProps = { parentId?: string | null; collectionType?: string | null; query?: string; -} +}; /* * React component to display search result rows for live tv library search diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx index 720cee0e3c..731cc6ec35 100644 --- a/src/components/search/SearchResults.tsx +++ b/src/components/search/SearchResults.tsx @@ -12,7 +12,7 @@ type SearchResultsProps = { parentId?: string | null; collectionType?: string | null; query?: string; -} +}; const ensureNonNullItems = (result: BaseItemDtoQueryResult) => ({ ...result, diff --git a/src/components/search/SearchResultsRow.tsx b/src/components/search/SearchResultsRow.tsx index 9dbb330578..0e5c1a50a4 100644 --- a/src/components/search/SearchResultsRow.tsx +++ b/src/components/search/SearchResultsRow.tsx @@ -35,13 +35,13 @@ type CardOptions = { showChannelName?: boolean, showTitle?: boolean, showYear?: boolean -} +}; type SearchResultsRowProps = { title?: string; items?: BaseItemDto[]; cardOptions?: CardOptions; -} +}; const SearchResultsRow: FunctionComponent = ({ title, items = [], cardOptions = {} }: SearchResultsRowProps) => { const element = useRef(null); diff --git a/src/components/search/SearchSuggestions.tsx b/src/components/search/SearchSuggestions.tsx index d16cdca8e6..7e70d19ee5 100644 --- a/src/components/search/SearchSuggestions.tsx +++ b/src/components/search/SearchSuggestions.tsx @@ -25,7 +25,7 @@ const createSuggestionLink = ({ name, href }: { name: string, href: string }) => type SearchSuggestionsProps = { parentId?: string | null; -} +}; const SearchSuggestions: FunctionComponent = ({ parentId }: SearchSuggestionsProps) => { const [ suggestions, setSuggestions ] = useState([]); diff --git a/src/elements/ButtonElement.tsx b/src/elements/ButtonElement.tsx index 3de90f0c11..f9ed58954b 100644 --- a/src/elements/ButtonElement.tsx +++ b/src/elements/ButtonElement.tsx @@ -21,7 +21,7 @@ type IProps = { title?: string; leftIcon?: string; rightIcon?: string; -} +}; const ButtonElement: FunctionComponent = ({ type, id, className, title, leftIcon, rightIcon }: IProps) => { return ( diff --git a/src/elements/CheckBoxElement.tsx b/src/elements/CheckBoxElement.tsx index fade823891..c8d861a0bb 100644 --- a/src/elements/CheckBoxElement.tsx +++ b/src/elements/CheckBoxElement.tsx @@ -29,7 +29,7 @@ type IProps = { itemCheckedAttribute?: string; itemName?: string title?: string -} +}; const CheckBoxElement: FunctionComponent = ({ labelClassName, className, elementId, dataFilter, itemType, itemId, itemAppName, itemCheckedAttribute, itemName, title }: IProps) => { const appName = itemAppName ? `- ${itemAppName}` : ''; diff --git a/src/elements/IconButtonElement.tsx b/src/elements/IconButtonElement.tsx index b39847403b..50b4d76f6e 100644 --- a/src/elements/IconButtonElement.tsx +++ b/src/elements/IconButtonElement.tsx @@ -10,7 +10,7 @@ type IProps = { dataIndex?: string | number; dataTag?: string | number; dataProfileid?: string | number; -} +}; const createIconButtonElement = ({ is, id, className, title, icon, dataIndex, dataTag, dataProfileid }: IProps) => ({ __html: `