refactor(core): use @snowluma/common/coerce in config normalizers
Phase 2. notifications/config and webui/ui-config dropped their verbatim- duplicated isObject/boolOr/clampInt (+ ui-config clampNum) in favor of the shared @snowluma/common/coerce. Pure delete-and-import: the shared primitives are byte-identical to the originals (adversarially verified), so behavior is unchanged. Kept local: strOr (notifications-only), oneOf/isFiniteNum/hexOr (ui-specific). notifications-config suite green (21), core+common typecheck clean.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
//
|
||||
// Channels are GLOBAL (defined once here); each UIN opts into a subset via
|
||||
// `OneBotConfig.notifications.channelIds` (see packages/onebot/src/config.ts).
|
||||
import { boolOr, clampInt, isObject } from '@snowluma/common/coerce';
|
||||
import { createLogger } from '@snowluma/common/logger';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
@@ -92,21 +93,9 @@ export function renderTemplate(template: string, vars: Record<string, string>):
|
||||
});
|
||||
}
|
||||
|
||||
// ─── Normalization helpers (replicated from ui-config conventions) ──────────
|
||||
|
||||
function isObject(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function boolOr(value: unknown, fallback: boolean): boolean {
|
||||
return typeof value === 'boolean' ? value : fallback;
|
||||
}
|
||||
|
||||
function clampInt(value: unknown, min: number, max: number, fallback: number): number {
|
||||
const n = typeof value === 'number' ? value : typeof value === 'string' ? Number(value) : NaN;
|
||||
if (!Number.isFinite(n)) return fallback;
|
||||
return Math.trunc(Math.min(max, Math.max(min, n)));
|
||||
}
|
||||
// ─── Normalization helpers ──────────────────────────────────────────────────
|
||||
// isObject / boolOr / clampInt come from @snowluma/common/coerce. strOr is
|
||||
// notifications-only (string truncation to maxLen), so it stays here.
|
||||
|
||||
function strOr(value: unknown, fallback: string, maxLen: number): string {
|
||||
return typeof value === 'string' ? value.slice(0, maxLen) : fallback;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { boolOr, clampInt, clampNum, isObject } from '@snowluma/common/coerce';
|
||||
import { createLogger } from '@snowluma/common/logger';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
@@ -308,10 +309,8 @@ function defaultPages(): UiPages {
|
||||
}
|
||||
|
||||
// ─── Normalization helpers ─────────────────────────────────────────────────
|
||||
|
||||
function isObject(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
}
|
||||
// isObject / boolOr / clampNum / clampInt come from @snowluma/common/coerce.
|
||||
// oneOf (enum), isFiniteNum, and hexOr (CSS color) are ui-specific and stay.
|
||||
|
||||
function oneOf<T extends string>(value: unknown, allowed: readonly T[], fallback: T): T {
|
||||
return typeof value === 'string' && (allowed as readonly string[]).includes(value)
|
||||
@@ -319,25 +318,11 @@ function oneOf<T extends string>(value: unknown, allowed: readonly T[], fallback
|
||||
: fallback;
|
||||
}
|
||||
|
||||
function clampNum(value: unknown, min: number, max: number, fallback: number): number {
|
||||
const n = typeof value === 'number' ? value : typeof value === 'string' ? Number(value) : NaN;
|
||||
if (!Number.isFinite(n)) return fallback;
|
||||
return Math.min(max, Math.max(min, n));
|
||||
}
|
||||
|
||||
function clampInt(value: unknown, min: number, max: number, fallback: number): number {
|
||||
return Math.trunc(clampNum(value, min, max, fallback));
|
||||
}
|
||||
|
||||
function isFiniteNum(value: unknown): boolean {
|
||||
if (typeof value === 'number') return Number.isFinite(value);
|
||||
return typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value));
|
||||
}
|
||||
|
||||
function boolOr(value: unknown, fallback: boolean): boolean {
|
||||
return typeof value === 'boolean' ? value : fallback;
|
||||
}
|
||||
|
||||
const HEX_RE = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
||||
function hexOr(value: unknown, fallback: string): string {
|
||||
return typeof value === 'string' && HEX_RE.test(value.trim()) ? value.trim() : fallback;
|
||||
|
||||
Reference in New Issue
Block a user