import { Dirent } from 'fs'; import fsPromises from 'fs/promises'; import path from 'path'; import { shouldNormalize } from './filter'; import type { FilterOptions } from './filter'; export interface ScanEntry { path: string; type: 'file' | 'directory'; } /** * 디렉토리를 재귀적으로 스캔해 NFD→NFC 변환이 필요한 항목을 반환한다. * 깊이 역순으로 정렬해 자식부터 rename할 수 있게 한다 (부모 경로 무효화 방지). */ export async function scan( dirPath: string, recursive: boolean, opts?: FilterOptions ): Promise { const entries: ScanEntry[] = []; await walk(dirPath, recursive, entries, opts); // 경로 깊이 역순: 하위 항목이 먼저 오도록 entries.sort((a, b) => b.path.split(path.sep).length - a.path.split(path.sep).length); return entries; } async function walk( dir: string, recursive: boolean, entries: ScanEntry[], opts?: FilterOptions ): Promise { let dirents: Dirent[]; try { dirents = await fsPromises.readdir(dir, { withFileTypes: true }); } catch { return; } for (const dirent of dirents) { const fullPath = path.join(dir, dirent.name); if (shouldNormalize(dirent.name, opts)) { entries.push({ path: fullPath, type: dirent.isDirectory() ? 'directory' : 'file' }); } if (recursive && dirent.isDirectory()) { await walk(fullPath, recursive, entries, opts); } } }