mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 15:25:46 +00:00
chore(eslint): add ESLint toolchain and clean src to strict 0/0 (#1165)
* chore(eslint): add eslint toolchain and configs * fix(eslint): resolve gradual-config errors (rules-of-hooks, no-empty, prefer-const, …) * chore(eslint): clear unused vars in config, contexts, app and test * chore(eslint): clear unused vars in api and music-network * chore(eslint): clear unused vars in utils * chore(eslint): clear unused vars in store * chore(eslint): clear unused vars in cover and hooks * chore(eslint): clear unused vars in components * chore(eslint): clear unused vars in pages * chore(eslint): remove explicit any in src * chore(eslint): align react-hooks exhaustive-deps * chore(eslint): zero gradual config on src * chore(eslint): strict hook rules in store and utils * chore(eslint): strict hook rules in hooks and cover * chore(eslint): strict hook rules in components * chore(eslint): strict hook rules in pages and contexts * chore(eslint): document scripts ignore in eslint config * chore(eslint): add lint script and zero strict findings * chore(eslint): address review round 1 (gradual 0/0, per-site disable reasons) * chore(eslint): tighten two set-state disable comments (review round 2 LOW) * chore(nix): sync npmDepsHash with package-lock.json * docs(changelog): add Under the Hood entry for ESLint setup (PR #1165) --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { MusicNetworkRuntime } from './MusicNetworkRuntime';
|
||||
import type { MusicNetworkStore, RuntimeHost } from './store';
|
||||
import { __resetWires, registerWire } from '../registry/wireRegistry';
|
||||
|
||||
@@ -38,8 +38,8 @@ function toArray<T>(v: T | T[] | undefined | null): T[] {
|
||||
return Array.isArray(v) ? v : [v];
|
||||
}
|
||||
|
||||
function topTags(raw: any, max = 5): string[] {
|
||||
return toArray(raw).map((tg: any) => String(tg.name)).slice(0, max);
|
||||
function topTags(raw: unknown, max = 5): string[] {
|
||||
return toArray(raw).map(tg => String((tg as { name?: unknown }).name)).slice(0, max);
|
||||
}
|
||||
|
||||
class AudioscrobblerWireImpl implements EnrichmentWire {
|
||||
@@ -181,7 +181,7 @@ class AudioscrobblerWireImpl implements EnrichmentWire {
|
||||
async getSimilarArtists(ctx: WireContext, name: string): Promise<string[]> {
|
||||
try {
|
||||
const data = await audioscrobblerCall(ctx, { method: 'artist.getSimilar', artist: name, limit: '50' }, false, true);
|
||||
return toArray(data?.similarartists?.artist).map((a: any) => a.name as string);
|
||||
return toArray(data?.similarartists?.artist).map(a => a.name as string);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
@@ -257,7 +257,7 @@ class AudioscrobblerWireImpl implements EnrichmentWire {
|
||||
period,
|
||||
limit: String(limit),
|
||||
}, false, true);
|
||||
return toArray(data?.[collection]?.[node]).map((it: any) => ({
|
||||
return toArray(data?.[collection]?.[node]).map(it => ({
|
||||
name: it.name,
|
||||
playcount: it.playcount,
|
||||
...(kind === 'artists' ? {} : { artist: it.artist?.name ?? '' }),
|
||||
@@ -275,7 +275,7 @@ class AudioscrobblerWireImpl implements EnrichmentWire {
|
||||
sk: ctx.sessionKey,
|
||||
limit: String(limit),
|
||||
}, false, true);
|
||||
return toArray(data?.recenttracks?.track).map((t: any) => ({
|
||||
return toArray(data?.recenttracks?.track).map(t => ({
|
||||
name: t.name,
|
||||
artist: t.artist?.['#text'] ?? t.artist?.name ?? '',
|
||||
album: t.album?.['#text'] ?? '',
|
||||
|
||||
@@ -26,12 +26,18 @@ const SESSION_INVALID_MESSAGE = /authentication failed|invalid (session|token)/i
|
||||
/**
|
||||
* Calls the Audioscrobbler endpoint. `sign` adds an api_sig; `get` uses GET
|
||||
* instead of a form POST. Throws MusicNetworkError on failure.
|
||||
*
|
||||
* Returns the raw decoded JSON. Last.fm / Audioscrobbler responses are
|
||||
* deeply-nested, loosely-documented and vary per method; the wire narrows and
|
||||
* coerces fields at each use, so precisely typing every response is not
|
||||
* tractable for this external API we do not control.
|
||||
*/
|
||||
export async function audioscrobblerCall(
|
||||
ep: AudioscrobblerEndpoint,
|
||||
params: Record<string, string>,
|
||||
sign = false,
|
||||
get = false,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- external Last.fm JSON, shape not under our control (see doc above)
|
||||
): Promise<any> {
|
||||
const entries = Object.entries(params) as [string, string][];
|
||||
return invokeTransport(
|
||||
|
||||
@@ -65,7 +65,7 @@ class ListenBrainzWireImpl implements ScrobbleWire {
|
||||
const caps: CapabilitySet = {};
|
||||
try {
|
||||
const data = await listenBrainzCall(endpoint(ctx), '/1/validate-token');
|
||||
const valid = data?.valid === true;
|
||||
const valid = (data as { valid?: boolean })?.valid === true;
|
||||
caps.scrobble = { status: valid ? 'yes' : 'error', message: valid ? undefined : 'Token invalid' };
|
||||
caps.nowPlaying = { status: valid ? 'yes' : 'error' };
|
||||
} catch (e) {
|
||||
|
||||
@@ -19,7 +19,7 @@ export async function listenBrainzCall(
|
||||
ep: ListenBrainzEndpoint,
|
||||
path: string,
|
||||
jsonBody?: unknown,
|
||||
): Promise<any> {
|
||||
): Promise<unknown> {
|
||||
return invokeTransport(
|
||||
'listenbrainz_request',
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ export async function malojaCall(
|
||||
path: string,
|
||||
jsonBody?: unknown,
|
||||
query: [string, string][] = [],
|
||||
): Promise<any> {
|
||||
): Promise<unknown> {
|
||||
return invokeTransport(
|
||||
'maloja_request',
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface TransportAuthRule {
|
||||
* Invoke a provider transport command. On failure, throws the auth-class
|
||||
* MusicNetworkError when `auth.match` recognises the message, otherwise NETWORK.
|
||||
*/
|
||||
export async function invokeTransport<T = any>(
|
||||
export async function invokeTransport<T = unknown>(
|
||||
command: string,
|
||||
args: Record<string, unknown>,
|
||||
auth?: TransportAuthRule,
|
||||
|
||||
Reference in New Issue
Block a user