refactor: deduplicate ensureDir into shared/fs-utils

5 copies of mkdir-p-if-not-exists consolidated into one shared module
with ensureDir (directory path) and ensureDirForFile (file path) variants.
This commit is contained in:
2026-03-28 10:42:21 -07:00
parent ab315c737f
commit 86b50dcb70
6 changed files with 22 additions and 39 deletions

View File

@@ -1,6 +1,6 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path';
import * as electron from 'electron'; import * as electron from 'electron';
import { ensureDirForFile } from '../../../shared/fs-utils';
interface PersistedTokenPayload { interface PersistedTokenPayload {
encryptedToken?: string; encryptedToken?: string;
@@ -21,15 +21,8 @@ export interface SafeStorageLike {
getSelectedStorageBackend?: () => string; getSelectedStorageBackend?: () => string;
} }
function ensureDirectory(filePath: string): void {
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
function writePayload(filePath: string, payload: PersistedTokenPayload): void { function writePayload(filePath: string, payload: PersistedTokenPayload): void {
ensureDirectory(filePath); ensureDirForFile(filePath);
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf-8'); fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf-8');
} }

View File

@@ -1,5 +1,5 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import { ensureDirForFile } from '../../../shared/fs-utils';
const INITIAL_BACKOFF_MS = 30_000; const INITIAL_BACKOFF_MS = 30_000;
const MAX_BACKOFF_MS = 6 * 60 * 60 * 1000; const MAX_BACKOFF_MS = 6 * 60 * 60 * 1000;
@@ -35,13 +35,6 @@ export interface AnilistUpdateQueue {
getSnapshot: (nowMs?: number) => AnilistRetryQueueSnapshot; getSnapshot: (nowMs?: number) => AnilistRetryQueueSnapshot;
} }
function ensureDir(filePath: string): void {
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
function clampBackoffMs(attemptCount: number): number { function clampBackoffMs(attemptCount: number): number {
const computed = INITIAL_BACKOFF_MS * Math.pow(2, Math.max(0, attemptCount - 1)); const computed = INITIAL_BACKOFF_MS * Math.pow(2, Math.max(0, attemptCount - 1));
return Math.min(MAX_BACKOFF_MS, computed); return Math.min(MAX_BACKOFF_MS, computed);
@@ -60,7 +53,7 @@ export function createAnilistUpdateQueue(
const persist = () => { const persist = () => {
try { try {
ensureDir(filePath); ensureDirForFile(filePath);
const payload: AnilistRetryQueuePayload = { pending, deadLetter }; const payload: AnilistRetryQueuePayload = { pending, deadLetter };
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf-8'); fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf-8');
} catch (error) { } catch (error) {

View File

@@ -1,6 +1,6 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path';
import electron from 'electron'; import electron from 'electron';
import { ensureDirForFile } from '../../shared/fs-utils';
const { safeStorage } = electron; const { safeStorage } = electron;
@@ -27,15 +27,8 @@ export interface JellyfinTokenStore {
clearSession: () => void; clearSession: () => void;
} }
function ensureDirectory(filePath: string): void {
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}
function writePayload(filePath: string, payload: PersistedSessionPayload): void { function writePayload(filePath: string, payload: PersistedSessionPayload): void {
ensureDirectory(filePath); ensureDirForFile(filePath);
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf-8'); fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf-8');
} }

View File

@@ -1,6 +1 @@
import * as fs from 'fs'; export { ensureDir } from '../../shared/fs-utils';
export function ensureDir(dirPath: string): void {
if (fs.existsSync(dirPath)) return;
fs.mkdirSync(dirPath, { recursive: true });
}

View File

@@ -1,5 +1,6 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { ensureDir } from '../../shared/fs-utils';
import type { AnilistCharacterDictionaryProfileScope } from '../../types'; import type { AnilistCharacterDictionaryProfileScope } from '../../types';
import type { import type {
CharacterDictionarySnapshotProgressCallbacks, CharacterDictionarySnapshotProgressCallbacks,
@@ -63,12 +64,6 @@ export interface CharacterDictionaryAutoSyncRuntimeDeps {
onSyncComplete?: (result: { mediaId: number; mediaTitle: string; changed: boolean }) => void; onSyncComplete?: (result: { mediaId: number; mediaTitle: string; changed: boolean }) => void;
} }
function ensureDir(dirPath: string): void {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
function normalizeMediaId(rawMediaId: number): number | null { function normalizeMediaId(rawMediaId: number): number | null {
const mediaId = Math.max(1, Math.floor(rawMediaId)); const mediaId = Math.max(1, Math.floor(rawMediaId));
return Number.isFinite(mediaId) ? mediaId : null; return Number.isFinite(mediaId) ? mediaId : null;

14
src/shared/fs-utils.ts Normal file
View File

@@ -0,0 +1,14 @@
import fs from 'node:fs';
import path from 'node:path';
export function ensureDir(dirPath: string): void {
if (fs.existsSync(dirPath)) return;
fs.mkdirSync(dirPath, { recursive: true });
}
export function ensureDirForFile(filePath: string): void {
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
}