summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorWolfgang Müller2025-03-26 19:40:28 +0100
committerWolfgang Müller2025-03-26 19:40:28 +0100
commitf8e2f64316354b36099a01eef0735ec0970f5b99 (patch)
tree548c1292db012355a559f1f33500d799f22c2d70
parent820d976d9d288c37dcf36cf3227508362dd46dff (diff)
downloadhircine-f8e2f64316354b36099a01eef0735ec0970f5b99.tar.gz
frontend: Migrate to eslint-plugin-svelte 3.0
This includes a migration to a flat eslint.config.js, which will now also automatically ignore items from .gitignore. eslint-plugin-svelte 3.0 comes with a couple of changes to recommended rules as well, these are also addressed in this commit.
-rw-r--r--frontend/eslint.config.js37
-rw-r--r--frontend/eslint.config.mjs99
-rw-r--r--frontend/package-lock.json165
-rw-r--r--frontend/package.json6
-rw-r--r--frontend/src/gql/Utils.ts2
-rw-r--r--frontend/src/lib/Shortcuts.ts2
-rw-r--r--frontend/src/lib/Toasts.ts2
-rw-r--r--frontend/src/lib/Utils.ts1
-rw-r--r--frontend/src/lib/components/Dialog.svelte1
-rw-r--r--frontend/src/lib/dialogs/ConfirmDeletion.svelte2
-rw-r--r--frontend/src/lib/dialogs/components/UpdateModeSelector.svelte2
-rw-r--r--frontend/src/lib/gallery/Gallery.svelte2
-rw-r--r--frontend/src/lib/pagination/Pagination.svelte2
-rw-r--r--frontend/src/lib/reader/PageView.svelte3
-rw-r--r--frontend/src/lib/scraper/ComicScrapeForm.svelte3
-rw-r--r--frontend/src/lib/scraper/components/SelectorGroup.svelte1
-rw-r--r--frontend/src/lib/tabs/ArchiveDetails.svelte2
-rw-r--r--frontend/src/lib/tabs/ArchiveEdit.svelte2
-rw-r--r--frontend/src/lib/tabs/Tabs.svelte2
-rw-r--r--frontend/src/lib/toolbar/SelectItems.svelte2
-rw-r--r--frontend/src/lib/toolbar/SelectSort.svelte2
-rw-r--r--frontend/src/routes/+page.svelte6
22 files changed, 159 insertions, 187 deletions
diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js
new file mode 100644
index 0000000..308fe8a
--- /dev/null
+++ b/frontend/eslint.config.js
@@ -0,0 +1,37 @@
+import { includeIgnoreFile } from '@eslint/compat';
+import js from '@eslint/js';
+import prettier from 'eslint-config-prettier';
+import svelte from 'eslint-plugin-svelte';
+import globals from 'globals';
+import { fileURLToPath } from 'node:url';
+import ts from 'typescript-eslint';
+import svelteConfig from './svelte.config.js';
+
+const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
+
+export default ts.config(
+ includeIgnoreFile(gitignorePath),
+ js.configs.recommended,
+ ...ts.configs.recommended,
+ ...svelte.configs.recommended,
+ prettier,
+ ...svelte.configs.prettier,
+ {
+ languageOptions: {
+ globals: { ...globals.browser, ...globals.node }
+ },
+ rules: { 'no-undef': 'off' }
+ },
+ {
+ files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
+ ignores: ['eslint.config.js', 'svelte.config.js'],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ extraFileExtensions: ['.svelte'],
+ parser: ts.parser,
+ svelteConfig
+ }
+ }
+ }
+);
diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs
deleted file mode 100644
index 9e842a8..0000000
--- a/frontend/eslint.config.mjs
+++ /dev/null
@@ -1,99 +0,0 @@
-import { FlatCompat } from '@eslint/eslintrc';
-import js from '@eslint/js';
-import typescriptEslint from '@typescript-eslint/eslint-plugin';
-import tsParser from '@typescript-eslint/parser';
-import globals from 'globals';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-import parser from 'svelte-eslint-parser';
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-const compat = new FlatCompat({
- baseDirectory: __dirname,
- recommendedConfig: js.configs.recommended,
- allConfig: js.configs.all
-});
-
-export default [
- {
- ignores: [
- '**/*.cjs',
- '**/.DS_Store',
- '**/node_modules',
- 'build',
- '.svelte-kit',
- 'package',
- '**/.env',
- '**/.env.*',
- '!**/.env.example',
- 'coverage',
- '**/pnpm-lock.yaml',
- '**/package-lock.json',
- '**/yarn.lock',
- 'src/gql',
- 'eslint.config.mjs'
- ]
- },
- ...compat.extends(
- 'eslint:recommended',
- 'plugin:@typescript-eslint/recommended-type-checked',
- 'plugin:@typescript-eslint/stylistic-type-checked',
- 'plugin:svelte/recommended',
- 'prettier'
- ),
- {
- plugins: {
- '@typescript-eslint': typescriptEslint
- },
-
- languageOptions: {
- globals: {
- ...globals.browser,
- ...globals.node
- },
-
- parser: tsParser,
- ecmaVersion: 2022,
- sourceType: 'module',
-
- parserOptions: {
- extraFileExtensions: ['.svelte'],
- project: true,
- tsconfigRootDir: '/home/wolf/src/wolf/hircine/frontend'
- }
- },
-
- rules: {
- 'no-console': 'warn',
- eqeqeq: 'error'
- }
- },
- {
- files: ['**/*.svelte'],
-
- languageOptions: {
- parser: parser,
- ecmaVersion: 5,
- sourceType: 'script',
-
- parserOptions: {
- parser: '@typescript-eslint/parser'
- }
- },
-
- rules: {
- '@typescript-eslint/no-unsafe-argument': 'off',
- '@typescript-eslint/no-unsafe-assignment': 'off',
- '@typescript-eslint/no-unsafe-call': 'off',
- '@typescript-eslint/no-unsafe-enum-comparison': 'off',
- '@typescript-eslint/no-unsafe-member-access': 'off',
- '@typescript-eslint/no-unused-expressions': 'off',
- 'no-undef': 'off'
- }
- },
- ...compat.extends('plugin:@typescript-eslint/disable-type-checked').map((config) => ({
- ...config,
- files: ['**/codegen.ts', '**/svelte.config.js']
- }))
-];
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 349a0a2..bc5d7cf 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -17,6 +17,7 @@
"svelte-modals": "^2.0.0"
},
"devDependencies": {
+ "@eslint/compat": "^1.2.5",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0",
"@graphql-codegen/cli": "^5.0.3",
@@ -28,13 +29,11 @@
"@sveltejs/kit": "^2.8.1",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/vite": "^4.0.6",
- "@typescript-eslint/eslint-plugin": "^8.14.0",
- "@typescript-eslint/parser": "^8.14.0",
"@zerodevx/svelte-toast": "^0.9.6",
"date-fns": "^4.1.0",
"eslint": "^9.14.0",
"eslint-config-prettier": "^10.0.0",
- "eslint-plugin-svelte": "^2.46.0",
+ "eslint-plugin-svelte": "^3.0.0",
"fast-deep-equal": "^3.1.3",
"globals": "^16.0.0",
"jsdom": "^26.0.0",
@@ -47,6 +46,7 @@
"tailwindcss": "^4.0.0",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
+ "typescript-eslint": "^8.28.0",
"vite": "^6.0.0",
"vitest": "^3.0.0"
}
@@ -1040,6 +1040,24 @@
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
+ "node_modules/@eslint/compat": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.7.tgz",
+ "integrity": "sha512-xvv7hJE32yhegJ8xNAnb62ggiAwTYHBpUCWhRxEj/ksvgDJuSXfoDkBcRYaYNFiJ+jH0IE3K16hd+xXzhBgNbg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "peerDependencies": {
+ "eslint": "^9.10.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@eslint/config-array": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz",
@@ -4620,9 +4638,9 @@
}
},
"node_modules/eslint-compat-utils": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz",
- "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==",
+ "version": "0.6.4",
+ "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.6.4.tgz",
+ "integrity": "sha512-/u+GQt8NMfXO8w17QendT4gvO5acfxQsAKirAt0LVxDnr2N8YLCVbregaNc/Yhp7NM128DwCaRvr8PLDfeNkQw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4662,32 +4680,31 @@
}
},
"node_modules/eslint-plugin-svelte": {
- "version": "2.46.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.46.1.tgz",
- "integrity": "sha512-7xYr2o4NID/f9OEYMqxsEQsCsj4KaMy4q5sANaKkAb6/QeCjYFxRmDm2S3YC3A3pl1kyPZ/syOx/i7LcWYSbIw==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.3.3.tgz",
+ "integrity": "sha512-imzGqIgWbfsb/CR14d3k3M8MiVNGet+l9mjPhvo1Rm0Nxi0rNn4/eELqyR8FWlgKBMlGkOp2kshRJm0xpxNfHQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@jridgewell/sourcemap-codec": "^1.4.15",
- "eslint-compat-utils": "^0.5.1",
+ "@eslint-community/eslint-utils": "^4.4.1",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "eslint-compat-utils": "^0.6.4",
"esutils": "^2.0.3",
"known-css-properties": "^0.35.0",
- "postcss": "^8.4.38",
+ "postcss": "^8.4.49",
"postcss-load-config": "^3.1.4",
- "postcss-safe-parser": "^6.0.0",
- "postcss-selector-parser": "^6.1.0",
- "semver": "^7.6.2",
- "svelte-eslint-parser": "^0.43.0"
+ "postcss-safe-parser": "^7.0.0",
+ "semver": "^7.6.3",
+ "svelte-eslint-parser": "^1.0.1"
},
"engines": {
- "node": "^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://github.com/sponsors/ota-meshi"
},
"peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0-0 || ^9.0.0-0",
+ "eslint": "^8.57.1 || ^9.0.0",
"svelte": "^3.37.0 || ^4.0.0 || ^5.0.0"
},
"peerDependenciesMeta": {
@@ -7280,20 +7297,30 @@
}
},
"node_modules/postcss-safe-parser": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz",
- "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
+ "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
"dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
"license": "MIT",
"engines": {
- "node": ">=12.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
+ "node": ">=18.0"
},
"peerDependencies": {
- "postcss": "^8.3.3"
+ "postcss": "^8.4.31"
}
},
"node_modules/postcss-scss": {
@@ -7324,9 +7351,9 @@
}
},
"node_modules/postcss-selector-parser": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
- "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+ "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8141,20 +8168,21 @@
}
},
"node_modules/svelte-eslint-parser": {
- "version": "0.43.0",
- "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.43.0.tgz",
- "integrity": "sha512-GpU52uPKKcVnh8tKN5P4UZpJ/fUDndmq7wfsvoVXsyP+aY0anol7Yqo01fyrlaWGMFfm4av5DyrjlaXdLRJvGA==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.1.0.tgz",
+ "integrity": "sha512-JP0v/wzDXWxza6c8K9ZjKKHYfgt0KidlbWx1e9n9UV4q+o28GTkk71fR0IDZDmLUDYs3vSq0+Tm9fofDqzGe1w==",
"dev": true,
"license": "MIT",
"dependencies": {
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "postcss": "^8.4.39",
- "postcss-scss": "^4.0.9"
+ "eslint-scope": "^8.2.0",
+ "eslint-visitor-keys": "^4.0.0",
+ "espree": "^10.0.0",
+ "postcss": "^8.4.49",
+ "postcss-scss": "^4.0.9",
+ "postcss-selector-parser": "^7.0.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://github.com/sponsors/ota-meshi"
@@ -8168,36 +8196,14 @@
}
}
},
- "node_modules/svelte-eslint-parser/node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/svelte-eslint-parser/node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "node_modules/svelte-eslint-parser/node_modules/eslint-visitor-keys": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
+ "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
"dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "acorn": "^8.9.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
- },
+ "license": "Apache-2.0",
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
@@ -8500,6 +8506,29 @@
"node": ">=14.17"
}
},
+ "node_modules/typescript-eslint": {
+ "version": "8.28.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.28.0.tgz",
+ "integrity": "sha512-jfZtxJoHm59bvoCMYCe2BM0/baMswRhMmYhy+w6VfcyHrjxZ0OJe0tGasydCpIpA+A/WIJhTyZfb3EtwNC/kHQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.28.0",
+ "@typescript-eslint/parser": "8.28.0",
+ "@typescript-eslint/utils": "8.28.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <5.9.0"
+ }
+ },
"node_modules/ua-parser-js": {
"version": "1.0.40",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 4c7d8ad..094cf39 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -15,6 +15,7 @@
"test": "vitest"
},
"devDependencies": {
+ "@eslint/compat": "^1.2.5",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0",
"@graphql-codegen/cli": "^5.0.3",
@@ -26,13 +27,11 @@
"@sveltejs/kit": "^2.8.1",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/vite": "^4.0.6",
- "@typescript-eslint/eslint-plugin": "^8.14.0",
- "@typescript-eslint/parser": "^8.14.0",
"@zerodevx/svelte-toast": "^0.9.6",
"date-fns": "^4.1.0",
"eslint": "^9.14.0",
"eslint-config-prettier": "^10.0.0",
- "eslint-plugin-svelte": "^2.46.0",
+ "eslint-plugin-svelte": "^3.0.0",
"fast-deep-equal": "^3.1.3",
"globals": "^16.0.0",
"jsdom": "^26.0.0",
@@ -45,6 +44,7 @@
"tailwindcss": "^4.0.0",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
+ "typescript-eslint": "^8.28.0",
"vite": "^6.0.0",
"vitest": "^3.0.0"
},
diff --git a/frontend/src/gql/Utils.ts b/frontend/src/gql/Utils.ts
index 177dff0..6fedd05 100644
--- a/frontend/src/gql/Utils.ts
+++ b/frontend/src/gql/Utils.ts
@@ -19,6 +19,7 @@ export function omitIdentifiers<T extends { __typename?: unknown; id: number }>(
return omit(obj, '__typename', 'id');
}
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isSuccess(object: any): object is gql.Success {
if (object.__typename === undefined) {
return false;
@@ -27,6 +28,7 @@ export function isSuccess(object: any): object is gql.Success {
return object.__typename.endsWith('Success') && (object as gql.Success).message !== undefined;
}
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isError(object: any): object is gql.Error {
if (object.__typename === undefined) {
return false;
diff --git a/frontend/src/lib/Shortcuts.ts b/frontend/src/lib/Shortcuts.ts
index 82f19ac..259500c 100644
--- a/frontend/src/lib/Shortcuts.ts
+++ b/frontend/src/lib/Shortcuts.ts
@@ -35,7 +35,7 @@ const modeSwitches = ['n', 'g', 'i', 'e'] as const;
type ModeSwitch = (typeof modeSwitches)[number];
function isModeSwitch(s: string): s is ModeSwitch {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
return modeSwitches.includes(s as any);
}
diff --git a/frontend/src/lib/Toasts.ts b/frontend/src/lib/Toasts.ts
index abc9a7d..224989b 100644
--- a/frontend/src/lib/Toasts.ts
+++ b/frontend/src/lib/Toasts.ts
@@ -15,5 +15,5 @@ export function toastError(message: string) {
});
}
-// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const toastFinally = (reason: any) => toastError(reason);
diff --git a/frontend/src/lib/Utils.ts b/frontend/src/lib/Utils.ts
index df7dad8..c347544 100644
--- a/frontend/src/lib/Utils.ts
+++ b/frontend/src/lib/Utils.ts
@@ -35,7 +35,6 @@ export function getResultState(state: OperationResultState): ResultState {
if (state.error) {
message = `${state.error.name}: ${state.error.message}`;
} else if (state.data) {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const obj = Object.values(state.data)[0];
if (isError(obj)) {
message = obj.message;
diff --git a/frontend/src/lib/components/Dialog.svelte b/frontend/src/lib/components/Dialog.svelte
index d300369..721d670 100644
--- a/frontend/src/lib/components/Dialog.svelte
+++ b/frontend/src/lib/components/Dialog.svelte
@@ -10,6 +10,7 @@
children?: Snippet;
}
+ // eslint-disable-next-line svelte/no-unused-props
let { isOpen, close, title, children }: Props = $props();
</script>
diff --git a/frontend/src/lib/dialogs/ConfirmDeletion.svelte b/frontend/src/lib/dialogs/ConfirmDeletion.svelte
index dde4ea7..53b1dd4 100644
--- a/frontend/src/lib/dialogs/ConfirmDeletion.svelte
+++ b/frontend/src/lib/dialogs/ConfirmDeletion.svelte
@@ -31,7 +31,7 @@
</p>
{#if multiple}
<ul class="mb-3 ml-8 list-disc">
- {#each names.slice(0, 10) as name}
+ {#each names.slice(0, 10) as name (name)}
<li>{name}</li>
{/each}
</ul>
diff --git a/frontend/src/lib/dialogs/components/UpdateModeSelector.svelte b/frontend/src/lib/dialogs/components/UpdateModeSelector.svelte
index 1a2307d..876657e 100644
--- a/frontend/src/lib/dialogs/components/UpdateModeSelector.svelte
+++ b/frontend/src/lib/dialogs/components/UpdateModeSelector.svelte
@@ -6,7 +6,7 @@
</script>
<div class="flex gap-1 pb-1 text-xs">
- {#each Object.entries(UpdateModeLabel) as [e, label]}
+ {#each Object.entries(UpdateModeLabel) as [e, label] (e)}
<button
type="button"
class:active={mode === e}
diff --git a/frontend/src/lib/gallery/Gallery.svelte b/frontend/src/lib/gallery/Gallery.svelte
index 0480026..f94747a 100644
--- a/frontend/src/lib/gallery/Gallery.svelte
+++ b/frontend/src/lib/gallery/Gallery.svelte
@@ -12,7 +12,7 @@
</script>
<div class="max-h-full gap-2 overflow-auto p-1 pr-3" tabindex="-1">
- {#each pages as page, index}
+ {#each pages as page, index (page.id)}
<GalleryPage {page} {index} {open} {updateCover} />
{/each}
</div>
diff --git a/frontend/src/lib/pagination/Pagination.svelte b/frontend/src/lib/pagination/Pagination.svelte
index fc2935c..28fbeb2 100644
--- a/frontend/src/lib/pagination/Pagination.svelte
+++ b/frontend/src/lib/pagination/Pagination.svelte
@@ -37,7 +37,7 @@
<Target disabled={leftmost} target={pagination.page - 1}>
<span class="icon-base icon-[material-symbols--keyboard-arrow-left]"></span>
</Target>
- {#each Array.from({ length: end + 1 - start }, (_, i) => i + start) as target}
+ {#each Array.from({ length: end + 1 - start }, (_, i) => i + start) as target (target)}
<Target active={pagination.page === target} {target}>
<p>{target.toString()}</p>
</Target>
diff --git a/frontend/src/lib/reader/PageView.svelte b/frontend/src/lib/reader/PageView.svelte
index 50c0873..4eb3d56 100644
--- a/frontend/src/lib/reader/PageView.svelte
+++ b/frontend/src/lib/reader/PageView.svelte
@@ -102,6 +102,7 @@
{@render pagesIn(currentChunk)}
</SliderMargin>
<div class:reverse class="flex w-full bg-gray-400/60 backdrop-blur-2xl">
+ <!-- eslint-disable-next-line svelte/require-each-key -->
{#each chunks as chunk, index}
<button
type="button"
@@ -123,7 +124,7 @@
</div>
<div class="invisible absolute">
- {#each pagesAround(reader.page) as page}
+ {#each pagesAround(reader.page) as page (page.id)}
<img src={src(page.image, 'full')} alt="" />
{/each}
</div>
diff --git a/frontend/src/lib/scraper/ComicScrapeForm.svelte b/frontend/src/lib/scraper/ComicScrapeForm.svelte
index 6cc3451..6f995a9 100644
--- a/frontend/src/lib/scraper/ComicScrapeForm.svelte
+++ b/frontend/src/lib/scraper/ComicScrapeForm.svelte
@@ -80,7 +80,7 @@
<Select
id="scrapers"
options={scrapers}
- placeholder={'Select scraper...'}
+ placeholder="Select scraper..."
bind:value={context.scraper}
/>
</div>
@@ -96,6 +96,7 @@
<div class="flex flex-col gap-2">
<h2 class="flex gap-1 border-b border-slate-700 text-base font-medium">Warnings</h2>
<ul class="ml-2 list-inside list-disc">
+ <!-- eslint-disable-next-line svelte/require-each-key -->
{#each context.warnings as warning}
<li>{warning}</li>
{/each}
diff --git a/frontend/src/lib/scraper/components/SelectorGroup.svelte b/frontend/src/lib/scraper/components/SelectorGroup.svelte
index 11489b1..5cf0cf0 100644
--- a/frontend/src/lib/scraper/components/SelectorGroup.svelte
+++ b/frontend/src/lib/scraper/components/SelectorGroup.svelte
@@ -32,6 +32,7 @@
</button>
</div>
<div class="flex flex-wrap gap-y-1">
+ <!-- eslint-disable-next-line svelte/require-each-key -->
{#each selectors as selector}
<SelectorButton {selector} />
{/each}
diff --git a/frontend/src/lib/tabs/ArchiveDetails.svelte b/frontend/src/lib/tabs/ArchiveDetails.svelte
index 1243162..c1ad68e 100644
--- a/frontend/src/lib/tabs/ArchiveDetails.svelte
+++ b/frontend/src/lib/tabs/ArchiveDetails.svelte
@@ -38,7 +38,7 @@
<div class="flex flex-col gap-1">
<h2 class="text-base font-medium">Comics</h2>
<div class="flex shrink-0 flex-col gap-4">
- {#each archive.comics as comic}
+ {#each archive.comics as comic (comic.id)}
<ComicCard compact {comic} />
{/each}
</div>
diff --git a/frontend/src/lib/tabs/ArchiveEdit.svelte b/frontend/src/lib/tabs/ArchiveEdit.svelte
index 2ed0523..c6ea684 100644
--- a/frontend/src/lib/tabs/ArchiveEdit.svelte
+++ b/frontend/src/lib/tabs/ArchiveEdit.svelte
@@ -55,7 +55,7 @@
<div class="flex flex-col gap-1">
<h2 class="text-base font-medium">Comics</h2>
<div class="flex shrink-0 flex-col gap-4">
- {#each archive.comics as comic}
+ {#each archive.comics as comic (comic.id)}
<ComicCard compact {comic}>
{#snippet overlay()}
<AddOverlay id={comic.id} />
diff --git a/frontend/src/lib/tabs/Tabs.svelte b/frontend/src/lib/tabs/Tabs.svelte
index c2b12af..59b3220 100644
--- a/frontend/src/lib/tabs/Tabs.svelte
+++ b/frontend/src/lib/tabs/Tabs.svelte
@@ -31,7 +31,7 @@
<div class="flex h-full max-h-full flex-col">
<nav>
<ul class="ms-1 me-3 flex border-b-2 border-slate-700 text-sm">
- {#each Object.entries(context.tabs) as [id, { title }]}
+ {#each Object.entries(context.tabs) as [id, { title }] (id)}
<li class="-mb-0.5">
<button
type="button"
diff --git a/frontend/src/lib/toolbar/SelectItems.svelte b/frontend/src/lib/toolbar/SelectItems.svelte
index 68a0652..ce8045e 100644
--- a/frontend/src/lib/toolbar/SelectItems.svelte
+++ b/frontend/src/lib/toolbar/SelectItems.svelte
@@ -14,7 +14,7 @@
</script>
<select class="btn-slate" value={pagination.items} {onchange} title="Limit displayed items to...">
- {#each values as value}
+ {#each values as value (value)}
<option {value}>{value}</option>
{/each}
</select>
diff --git a/frontend/src/lib/toolbar/SelectSort.svelte b/frontend/src/lib/toolbar/SelectSort.svelte
index 0e59df6..a7d56c7 100644
--- a/frontend/src/lib/toolbar/SelectSort.svelte
+++ b/frontend/src/lib/toolbar/SelectSort.svelte
@@ -41,7 +41,7 @@
<div class="rounded-group flex flex-row">
<select class="btn-slate" value={sort.on} {onchange} title="Sort on...">
- {#each Object.entries(labels) as [value, label]}
+ {#each Object.entries(labels) as [value, label] (value)}
<option {value}>{label}</option>
{/each}
</select>
diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte
index 237b573..4b921bb 100644
--- a/frontend/src/routes/+page.svelte
+++ b/frontend/src/routes/+page.svelte
@@ -51,21 +51,21 @@
<div class="flex flex-col gap-8" in:fade={fadeDefault}>
{#if recent && recent.count > 0}
<Carousel title="Recently added" href={recentLink}>
- {#each recent.edges as comic}
+ {#each recent.edges as comic (comic.id)}
<ComicCard coverOnly {comic} />
{/each}
</Carousel>
{/if}
{#if favourites && favourites.count > 0}
<Carousel title="Favourites" href={favouriteLink}>
- {#each favourites.edges as comic}
+ {#each favourites.edges as comic (comic.id)}
<ComicCard coverOnly {comic} />
{/each}
</Carousel>
{/if}
{#if bookmarked && bookmarked.count > 0}
<Carousel title="Bookmarks" href={bookmarkLink}>
- {#each bookmarked.edges as comic}
+ {#each bookmarked.edges as comic (comic.id)}
<ComicCard coverOnly {comic} />
{/each}
</Carousel>