mirror of
https://github.com/FoxxMD/multi-scrobbler.git
synced 2026-09-02 21:03:09 +03:00
chore: Cleanup development comments
This commit is contained in:
@@ -20,11 +20,6 @@ export const clientDefaultsSchema = z.object({
|
||||
|
||||
export type ClientDefaults = z.infer<typeof clientDefaultsSchema>;
|
||||
|
||||
// `TransformOptions`/`TransformerCommonConfig<T,Y>` (from `../../../../core/Atomic.ts`) are only ever used at
|
||||
// their default type params (`Record<string, any>`) everywhere in the codebase, but `TransformerCommonConfig`
|
||||
// stays generic there and `TransformerCommon<T,Y> extends TransformerCommonConfig<T,Y>` - converting the
|
||||
// exported interface itself would break that extends clause. Reconstructed locally here instead, scoped to
|
||||
// this file's `transformers` field only.
|
||||
const transformOptionsSchema = z.object({
|
||||
failOnFetch: z.boolean().optional(),
|
||||
throwOnFailure: z.union([
|
||||
|
||||
@@ -6,9 +6,6 @@ export const statusTypeSchema = z.union([z.literal("online"), z.literal("idle"),
|
||||
|
||||
export type StatusType = z.infer<typeof statusTypeSchema>;
|
||||
|
||||
// `z.tuple([z.number(), z.string()])` in the installed zod version infers as `[number?, string?, ...unknown[]]`
|
||||
// rather than `[number, string]`, which breaks real consumers (e.g. DiscordIPCClient.ts) expecting a strict
|
||||
// 2-tuple. `z.custom` sidesteps the bug while still checking shape at runtime.
|
||||
const ipcLocationTupleSchema = z.custom<[number, string]>((val) => Array.isArray(val) && val.length === 2 && typeof val[0] === 'number' && typeof val[1] === 'string');
|
||||
|
||||
export const discordDataSchema = z.object({
|
||||
|
||||
@@ -46,11 +46,6 @@ export type MatchLoggingOptions = z.infer<typeof matchLoggingOptionsSchema>;
|
||||
|
||||
export const commonClientDataSchema = z.looseObject({});
|
||||
|
||||
// `z.infer` of an empty object schema (strict or loose) picks up a `never`/`unknown` index signature that a
|
||||
// plain empty TS interface never had, which breaks the many `interface FooData extends CommonClientData, ...`
|
||||
// declarations elsewhere (see the same fix applied to `CommonSourceData` in `../source/index.ts`). The
|
||||
// original `interface CommonClientData {}` is structurally identical to `{}` itself, so the type is declared
|
||||
// directly rather than derived from the schema for this one empty-shape case.
|
||||
export type CommonClientData = {};
|
||||
|
||||
export const upstreamRefreshOptionsSchema = z.object({
|
||||
@@ -188,6 +183,4 @@ export const commonClientConfigSchema = z.object({
|
||||
options: commonClientOptionsSchema.optional(),
|
||||
});
|
||||
|
||||
// `data`'s type is overridden here for the same reason `CommonClientData` is declared directly above rather
|
||||
// than derived from `commonClientDataSchema`.
|
||||
export type CommonClientConfig = Omit<z.infer<typeof commonClientConfigSchema>, 'data'> & { data?: CommonClientData };
|
||||
|
||||
@@ -8,10 +8,6 @@ export type RetentionPlayType = z.infer<typeof retentionPlayTypeSchema>;
|
||||
|
||||
export const retentionPlayTypes: RetentionPlayType[] = ['failed','completed','duped'];
|
||||
|
||||
// `Duration` (from `dayjs/plugin/duration.js`) is a class instance with dozens of methods (`asSeconds`,
|
||||
// `humanize`, `add`, `clone`, etc.), not a plain data shape - reconstructing its full interface as a zod
|
||||
// object wouldn't provide any real validation value. This checks for a Duration-shaped object via one of its
|
||||
// signature methods and relies on the imported type for full static typing.
|
||||
const durationSchema = z.custom<Duration>(
|
||||
(val) => val !== null && typeof val === 'object' && typeof (val as Duration).asMilliseconds === 'function',
|
||||
{message: 'Expected a dayjs Duration instance'}
|
||||
@@ -25,14 +21,6 @@ export const retentionValueSchema = z.union([durationSchema, z.literal(false)]);
|
||||
|
||||
export type RetentionValue = z.infer<typeof retentionValueSchema>;
|
||||
|
||||
// `RententionGranular<T>`, `RetentionConfigValue<T>`, `RetentionOption<T>`, and `RetentionConfig<T>` were
|
||||
// previously left as plain generics since zod can't represent a generic object schema the way a TS interface
|
||||
// can. In practice though each is only ever instantiated with one of three known terms - `DurationValue`,
|
||||
// `Duration`, and `RetentionValue` - so below builds one concrete schema per term actually valid for each
|
||||
// family (per each type's original generic constraint) and unifies them with `z.union` into a single
|
||||
// non-generic replacement. Call sites elsewhere now use the specific per-term type where the term is
|
||||
// statically known.
|
||||
|
||||
export const rententionGranularDurationValueSchema = z.object({
|
||||
failed: durationValueSchema.optional(),
|
||||
completed: durationValueSchema.optional(),
|
||||
@@ -93,8 +81,6 @@ export const COMPACTABLE = {
|
||||
|
||||
export const compactableProperties: CompactableProperty[] = [COMPACTABLE.transform, COMPACTABLE.input];
|
||||
|
||||
// `RetentionOption<T>`'s original constraint (`T extends RetentionValue`) only ever admits `Duration` and
|
||||
// `RetentionValue` itself - not `DurationValue` - so there are only two valid terms here.
|
||||
export const retentionOptionDurationSchema = z.object({
|
||||
failed: durationSchema,
|
||||
completed: durationSchema,
|
||||
|
||||
@@ -59,12 +59,8 @@ export const scrobbleThresholdsSchema = z.object({
|
||||
|
||||
export type ScrobbleThresholds = z.infer<typeof scrobbleThresholdsSchema>;
|
||||
|
||||
// `LogLevel` (from `@foxxmd/logging`) is a simple string-literal union, reconstructed directly.
|
||||
export const logLevelSchema = z.enum(["silent", "fatal", "error", "warn", "info", "log", "verbose", "debug", "trace"]);
|
||||
|
||||
// `FileLogOptions` (from `@foxxmd/logging`) extends `FileOptions`, which itself extends `PinoRollOptions` and
|
||||
// `RollOptions` - two levels deep, but all plain data fields, so it's reconstructed in full here rather than
|
||||
// stubbed.
|
||||
export const fileLogOptionsSchema = z.object({
|
||||
size: z.union([z.number(), z.string()]).optional(),
|
||||
frequency: z.union([z.literal('daily'), z.literal('hourly'), z.number()]).optional(),
|
||||
@@ -184,11 +180,6 @@ export type ManualListeningOptions = z.infer<typeof manualListeningOptionsSchema
|
||||
|
||||
export const commonSourceDataSchema = z.looseObject({});
|
||||
|
||||
// `z.infer` of an empty object schema (strict or loose) picks up a `never`/`unknown` index signature that a
|
||||
// plain empty TS interface never had, which breaks the many `interface FooData extends CommonSourceData, ...`
|
||||
// declarations elsewhere (some in the "extends" direction, some in the "assign a plain object" direction).
|
||||
// The original `interface CommonSourceData {}` is structurally identical to `{}` itself, so the type is
|
||||
// declared directly rather than derived from the schema for this one empty-shape case.
|
||||
export type CommonSourceData = {};
|
||||
|
||||
export const commonSourceConfigSchema = z.object({
|
||||
@@ -213,7 +204,4 @@ export const commonSourceConfigSchema = z.object({
|
||||
options: commonSourceOptionsSchema.optional(),
|
||||
});
|
||||
|
||||
// `data`'s type is overridden here for the same reason `CommonSourceData` is declared directly above rather
|
||||
// than derived from `commonSourceDataSchema` - the schema-inferred type carries an index signature that the
|
||||
// original empty `data?: CommonSourceData` field never had.
|
||||
export type CommonSourceConfig = Omit<z.infer<typeof commonSourceConfigSchema>, 'data'> & { data?: CommonSourceData };
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import * as z from "zod";
|
||||
import {commonSourceConfigSchema, commonSourceDataSchema, commonSourceOptionsSchema} from "./index.ts";
|
||||
|
||||
// `CollectionType`/`MediaType` (from `@jellyfin/sdk`) don't resolve cleanly - the package's typings don't
|
||||
// line up with its actual exports (see the `@ts-expect-error` this replaced). Represented as `string`/`string[]`
|
||||
// per instruction rather than chasing the SDK's broken typings.
|
||||
|
||||
export const jellyApiDataSchema = z.object({
|
||||
...commonSourceDataSchema.shape,
|
||||
/**
|
||||
|
||||
@@ -3,16 +3,7 @@ import type {SearchAndReplaceRegExp} from "@foxxmd/regex-buddy-core";
|
||||
import type { MarkRequired } from "ts-essentials";
|
||||
import { stripIndents } from "common-tags";
|
||||
|
||||
// The following generic types are used elsewhere in the codebase with several different concrete type
|
||||
// parameters (e.g. `PlayTransformHooks<ExternalMetadataTerm>`, `PlayTransformStage<SearchAndReplaceTerm[]>`,
|
||||
// `PlayTransformUserStage<ConditionalSearchAndReplaceRegExp[]>`). Zod schemas cannot be generic the way a
|
||||
// TypeScript interface can, so these are intentionally left as plain types. `PlayTransformOptions` and
|
||||
// `PlayTransformRules` below are instead built from concrete, hand-resolved zod schemas that represent one
|
||||
// specific instantiation of this generic machinery.
|
||||
|
||||
export type PlayTransformParts<T, Y = StageTyped> = Extract<PlayTransformStage<T>, Y> & Whennable;
|
||||
//export type PlayTransformUserParts<T> = PlayTransformUserStage<T[]> & { when?: WhenConditionsConfig };
|
||||
//export type PlayTransformMetaParts<T = ExternalMetadataTerm> = PlayTransformMetadataStage<T> & { when?: WhenConditionsConfig };
|
||||
export type PlayTransformPartsArray<T, Y = StageTyped> = PlayTransformParts<T, Y>[];
|
||||
|
||||
/** Represents the weakly-defined user config. May be an array of parts or one parts object
|
||||
@@ -94,16 +85,6 @@ export const TRANSFORM_HOOK = {
|
||||
export type WhenParts<T> = PlayTransformPartsAtomic<T>;
|
||||
export type WhenConditions<T> = WhenParts<T>[];
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
// Concrete zod schemas
|
||||
//
|
||||
// Everything below backs the non-generic types that the generic scaffolding above is built from/into.
|
||||
// `PlayTransformOptions` (raw user JSON) and `PlayTransformRules` (the strongly-typed runtime result) are
|
||||
// each a specific instantiation of `PlayTransformHooksConfig<T>` / `PlayTransformHooks<T>`. Rather than try
|
||||
// to make those interfaces themselves generic in zod, this section hand-resolves the two concrete `T`s that
|
||||
// matter (the user-facing term shape vs. the normalized rule-term shape) and builds each stage variant once
|
||||
// per instantiation.
|
||||
// --------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper used to construct a concrete `PlayTransformPartsAtomic<T>` schema for a given term schema, since
|
||||
// `PlayTransformPartsAtomic<T>` itself can't be represented generically in zod.
|
||||
@@ -140,9 +121,6 @@ export const whennableSchema = z.object({
|
||||
|
||||
export type Whennable = z.infer<typeof whennableSchema>;
|
||||
|
||||
// `SearchAndReplaceRegExp` (from `@foxxmd/regex-buddy-core`) declares `test?: (obj: SearchAndReplaceRegExp) => boolean`.
|
||||
// Zod can only structurally confirm this is a function, not validate its signature/behavior, so `z.custom` is
|
||||
// used as a best-effort check.
|
||||
export const conditionalSearchAndReplaceRegExpSchema = z.object({
|
||||
...whennableSchema.shape,
|
||||
/** The plain string or regex pattern to match */
|
||||
@@ -158,9 +136,6 @@ export const conditionalSearchAndReplaceRegExpSchema = z.object({
|
||||
// https://stackoverflow.com/a/77256318
|
||||
export type ConditionalSearchAndReplaceRegExp = MarkRequired<z.infer<typeof conditionalSearchAndReplaceRegExpSchema>, 'search'>;
|
||||
|
||||
// `Exclude<ConditionalSearchAndReplaceRegExp, 'test'>` is a no-op in the original type: `Exclude` only
|
||||
// removes union members, and `ConditionalSearchAndReplaceRegExp` is an object type, not a union containing
|
||||
// the literal `'test'`. So this type is identical to `ConditionalSearchAndReplaceRegExp`.
|
||||
const {
|
||||
test,
|
||||
...restConditionalRegSchema
|
||||
@@ -204,8 +179,6 @@ export const stageTypeUserSchema = z.literal('user').meta({title: 'Stage Type Us
|
||||
|
||||
export type StageTypeUser = z.infer<typeof stageTypeUserSchema>;
|
||||
|
||||
// `StageTypeMetadata | StageTypeUser | string` collapses to `string` (the literal members are absorbed by
|
||||
// the wider `string` member), so the schema is just `z.string()`.
|
||||
export const stageTypeSchema = z.string().meta({title: 'Stage Type'});
|
||||
|
||||
export type StageType = z.infer<typeof stageTypeSchema>;
|
||||
@@ -253,7 +226,6 @@ export const playTransformNativeStageSchema = z.object({
|
||||
|
||||
export type PlayTransformNativeStage = z.infer<typeof playTransformNativeStageSchema>;
|
||||
|
||||
// `type: any` stage, shared as-is between the Options and Rules pools below (it doesn't depend on the outer T).
|
||||
//const anyAtomicSchema = buildPartsAtomicSchema(z.any());
|
||||
// const playTransformGenericStageSchema = z.object({
|
||||
// ...stageConfigSchema.shape,
|
||||
@@ -261,8 +233,6 @@ export type PlayTransformNativeStage = z.infer<typeof playTransformNativeStageSc
|
||||
// type: stageTypeSchema,
|
||||
// }).meta({title: 'Transform Generic Stage'});
|
||||
|
||||
// `PlayTransformOptions` term shape: T = SearchAndReplaceTerm[] | ExternalMetadataTerm
|
||||
//const optionsPartsTermSchema = z.union([z.array(searchAndReplaceTermSchema), externalMetadataTermSchema]);
|
||||
const optionsAtomicSchema = buildPartsAtomicSchema(z.array(searchAndReplaceTermSchema));
|
||||
|
||||
const playTransformUserStageOptionsSchema = z.object({
|
||||
@@ -276,8 +246,6 @@ const playTransformUserStageOptionsSchema = z.object({
|
||||
// ...optionsAtomicSchema.shape,
|
||||
// }).meta({title: 'Transform User Stage'});
|
||||
|
||||
// `PlayTransformRules` term shape: T = ConditionalSearchAndReplaceRegExp[] | ExternalMetadataTerm
|
||||
//const rulesPartsTermSchema = z.union([z.array(conditionalSearchAndReplaceRegExpSchema), externalMetadataTermSchema]).meta({title: 'Rule Parts Term'});
|
||||
const rulesAtomicSchema = buildPartsAtomicSchema(z.array(searchAndReplaceTermSchema)).meta({title: 'Rules Atomic'});
|
||||
|
||||
const playTransformUserStageRulesSchema = z.object({
|
||||
@@ -286,20 +254,10 @@ const playTransformUserStageRulesSchema = z.object({
|
||||
type: z.literal('user'),
|
||||
}).meta({title: 'User Stage Rules'});
|
||||
|
||||
// zod's `discriminatedUnion` requires each branch's discriminant literal(s) to be unique across the whole
|
||||
// union. `StageTypeMetadata` nominally includes `'native'`, but `'native'`-typed stages are represented by
|
||||
// the dedicated, stricter `playTransformNativeStageSchema` (no `score` field) instead. This narrows the
|
||||
// metadata branch to `'spotify' | 'musicbrainz'` only for the purposes of this union - the overall set of
|
||||
// `type` values covered across the whole union is unchanged.
|
||||
const metadataStageForUnionSchema = playTransformMetadataStageSchema.extend({
|
||||
type: z.enum(['musicbrainz']),
|
||||
}).meta({title: 'Transform External Stage'});
|
||||
|
||||
// `PlayTransformParts<T, Y> = Extract<PlayTransformStage<T>, Y> & Whennable` - the `& Whennable` intersection
|
||||
// is redundant here since every stage schema already includes `when` via `stageConfigSchema`/`untypedStageConfigSchema`.
|
||||
|
||||
// Options pool: `Extract<PlayTransformStage<T>, MaybeStageTyped>` doesn't filter anything out, since every
|
||||
// member of `PlayTransformStage<T>` already structurally satisfies `StageTyped | NotStageTyped`.
|
||||
const playTransformTypedStageOptionsSchema = z.discriminatedUnion('type', [
|
||||
metadataStageForUnionSchema,
|
||||
playTransformNativeStageSchema,
|
||||
@@ -311,17 +269,11 @@ const playTransformTypedStageOptionsSchema = z.discriminatedUnion('type', [
|
||||
// untypedPlayTransformUserStageOptionsSchema,
|
||||
// ]).meta({title: 'Stage'});
|
||||
|
||||
// Rules pool: `Extract<PlayTransformStage<T>, StageTyped>` excludes `UntypedPlayTransformUserStage<T>`,
|
||||
// since it has no `type` field and so isn't assignable to `StageTyped`.
|
||||
const playTransformTypedStageRulesSchema = z.discriminatedUnion('type', [
|
||||
metadataStageForUnionSchema,
|
||||
playTransformNativeStageSchema,
|
||||
playTransformUserStageRulesSchema,
|
||||
]);
|
||||
// const playTransformStageRulesSchema = z.union([
|
||||
// playTransformTypedStageRulesSchema,
|
||||
// playTransformGenericStageSchema,
|
||||
// ]);
|
||||
|
||||
const playTransformPartsConfigOptionsSchema = z.union([
|
||||
z.array(playTransformTypedStageOptionsSchema),
|
||||
@@ -372,11 +324,6 @@ export const playTransformRulesSchema = z.object({
|
||||
|
||||
export type PlayTransformRules = z.infer<typeof playTransformRulesSchema>;
|
||||
|
||||
// Converting raw user JSON (`PlayTransformOptions`) into the normalized runtime shape (`PlayTransformRules`)
|
||||
// requires real business logic - assigning default `type`s to untyped user stages, normalizing the
|
||||
// single-object-or-array shorthand into arrays, and resolving bare string search/replace shorthand into full
|
||||
// `ConditionalSearchAndReplaceRegExp` objects. That logic already lives in
|
||||
// `AbstractComponent.transformPartToStrong` and is out of scope here, so this transform is stubbed only.
|
||||
export const playTransformOptionsToRulesSchema = playTransformOptionsSchema.transform((val): PlayTransformRules => {
|
||||
throw new Error('Not implemented: use AbstractComponent.transformPartToStrong for PlayTransformOptions -> PlayTransformRules normalization');
|
||||
}).meta({title: 'Transform Options to Rules'});
|
||||
|
||||
Reference in New Issue
Block a user