chore: stop lint rules that do not model runes from reporting
no-unused-expressions is off for Svelte files: a bare `book;` in an $effect declares a dependency. The URL and Set instances it flagged are local temporaries, marked individually. The one real finding was visibleApiKeys, genuine reactive state cloned on every mutation to force an update; it is a SvelteSet now.
This commit is contained in:
@@ -41,8 +41,15 @@ export default defineConfig(
|
|||||||
// no-useless-assignment joined eslint:recommended in ESLint 10, and its flow analysis
|
// no-useless-assignment joined eslint:recommended in ESLint 10, and its flow analysis
|
||||||
// does not model runes: it reads `let { ref = $bindable(null) } = $props()` as a value
|
// does not model runes: it reads `let { ref = $bindable(null) } = $props()` as a value
|
||||||
// that is never read. Deleting the default, as it suggests, breaks the binding.
|
// that is never read. Deleting the default, as it suggests, breaks the binding.
|
||||||
|
//
|
||||||
|
// no-unused-expressions is off for the same reason: a bare `book;` inside an $effect is
|
||||||
|
// how a reactive dependency is declared when the read would otherwise be untracked.
|
||||||
|
// Removing the statement stops the effect re-running.
|
||||||
files: ['**/*.svelte'],
|
files: ['**/*.svelte'],
|
||||||
rules: { 'no-useless-assignment': 'off' }
|
rules: {
|
||||||
|
'no-useless-assignment': 'off',
|
||||||
|
'@typescript-eslint/no-unused-expressions': 'off'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
|
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
|
||||||
|
|||||||
@@ -36,7 +36,6 @@
|
|||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
// whenever input value changes reset invalid
|
// whenever input value changes reset invalid
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
||||||
inputValue;
|
inputValue;
|
||||||
|
|
||||||
untrack(() => {
|
untrack(() => {
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ export class BookCollectionState {
|
|||||||
|
|
||||||
this.view = next;
|
this.view = next;
|
||||||
|
|
||||||
|
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- local temporary, not reactive state
|
||||||
const url = new URL(page.url);
|
const url = new URL(page.url);
|
||||||
url.searchParams.set('view', next);
|
url.searchParams.set('view', next);
|
||||||
// Not a route to resolve — this is the current URL with one query param
|
// Not a route to resolve — this is the current URL with one query param
|
||||||
@@ -138,6 +139,7 @@ export class BookCollectionState {
|
|||||||
|
|
||||||
updateSearchParams() {
|
updateSearchParams() {
|
||||||
// Update URL
|
// Update URL
|
||||||
|
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- local temporary, not reactive state
|
||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
|
|
||||||
Object.entries(this.filters).forEach(([filter, values]) => {
|
Object.entries(this.filters).forEach(([filter, values]) => {
|
||||||
@@ -215,6 +217,7 @@ export class BookCollectionState {
|
|||||||
// and skips every page in between.
|
// and skips every page in between.
|
||||||
this.currentBookPage = 1;
|
this.currentBookPage = 1;
|
||||||
|
|
||||||
|
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- local temporary, not reactive state
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
// Re-read sort and filter state from URL
|
// Re-read sort and filter state from URL
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export class BookOperationsState {
|
|||||||
|
|
||||||
async downloadBooks(bookIds: string[] | number[], filename?: string) {
|
async downloadBooks(bookIds: string[] | number[], filename?: string) {
|
||||||
// Construct the download URL
|
// Construct the download URL
|
||||||
|
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- local temporary, not reactive state
|
||||||
const downloadUrl = new URL(`/api/books/download`, page.url.origin);
|
const downloadUrl = new URL(`/api/books/download`, page.url.origin);
|
||||||
downloadUrl.searchParams.set('library_id', this.libraryId);
|
downloadUrl.searchParams.set('library_id', this.libraryId);
|
||||||
bookIds.forEach((id) => {
|
bookIds.forEach((id) => {
|
||||||
@@ -142,6 +143,7 @@ export class BookOperationsState {
|
|||||||
|
|
||||||
async downloadBookFile(bookId: number, fileId: number, filename: string) {
|
async downloadBookFile(bookId: number, fileId: number, filename: string) {
|
||||||
// Construct the download URL
|
// Construct the download URL
|
||||||
|
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- local temporary, not reactive state
|
||||||
const downloadUrl = new URL(`/api/books/download/${bookId}/${fileId}`, page.url.origin);
|
const downloadUrl = new URL(`/api/books/download/${bookId}/${fileId}`, page.url.origin);
|
||||||
this.download(downloadUrl, filename);
|
this.download(downloadUrl, filename);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ export class BookshelfState {
|
|||||||
if (!bookshelves) return;
|
if (!bookshelves) return;
|
||||||
|
|
||||||
// Create a Set of shelf IDs that need updating for efficient lookup
|
// Create a Set of shelf IDs that need updating for efficient lookup
|
||||||
|
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- local temporary, not reactive state
|
||||||
const shelfIdsToUpdate = new Set<number>();
|
const shelfIdsToUpdate = new Set<number>();
|
||||||
books.forEach((book) => {
|
books.forEach((book) => {
|
||||||
book.lists.forEach((shelf) => {
|
book.lists.forEach((shelf) => {
|
||||||
|
|||||||
@@ -21,11 +21,12 @@
|
|||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import { invalidateAll } from '$app/navigation';
|
import { invalidateAll } from '$app/navigation';
|
||||||
import type { Device } from '$lib/schema/device';
|
import type { Device } from '$lib/schema/device';
|
||||||
|
import { SvelteSet } from 'svelte/reactivity';
|
||||||
|
|
||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
|
|
||||||
let createDialogOpen = $state(false);
|
let createDialogOpen = $state(false);
|
||||||
let visibleApiKeys = $state<Set<string>>(new Set());
|
const visibleApiKeys = new SvelteSet<string>();
|
||||||
let deleteConfirmDevice = $state<Device | null>(null);
|
let deleteConfirmDevice = $state<Device | null>(null);
|
||||||
let regenerateConfirmDevice = $state<Device | null>(null);
|
let regenerateConfirmDevice = $state<Device | null>(null);
|
||||||
|
|
||||||
@@ -35,7 +36,6 @@
|
|||||||
} else {
|
} else {
|
||||||
visibleApiKeys.add(deviceId);
|
visibleApiKeys.add(deviceId);
|
||||||
}
|
}
|
||||||
visibleApiKeys = new Set(visibleApiKeys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function maskApiKey(apiKey: string): string {
|
function maskApiKey(apiKey: string): string {
|
||||||
|
|||||||
Reference in New Issue
Block a user