export type OnFileCallback = (file: File, path: string) => Promise; export async function traverseDirectoryTreeWrapper( fileList: DataTransferItemList, onFileCallback: OnFileCallback, ) { for (const dtItem of fileList) { if (dtItem) { await traverseDirectoryTree(dtItem.webkitGetAsEntry(), onFileCallback); } } } async function traverseDirectoryTree( item: FileSystemEntry | null, onFileCallback: OnFileCallback, path: string = '', ) { if (item?.isFile) { const fileItem = item as FileSystemFileEntry; await getFileEntriesFromReader(fileItem, onFileCallback, path); } else if (item?.isDirectory) { const directoryItem = item as FileSystemDirectoryEntry; const directoryReader = directoryItem.createReader(); let entries: Array = []; let lastAdditions = 0; do { const entrySet = await getDirectoryEntriesFromReader(directoryReader); lastAdditions = entrySet.length; entries = entries.concat(entrySet); } while (lastAdditions > 0); for (const element of entries) { await traverseDirectoryTree( element, onFileCallback, path + directoryItem.name + '/', ); } } } async function getDirectoryEntriesFromReader( directoryReader: FileSystemDirectoryReader, ): Promise> { return await new Promise((resolve, reject) => { directoryReader.readEntries((entries: Array) => { resolve(entries); }, reject); }); } async function getFileEntriesFromReader( item: FileSystemFileEntry, onFileCallback: OnFileCallback, path: string, ) { return await new Promise((resolve, _reject) => { item.file(async (file: File) => { await onFileCallback(file, path); resolve(); }); }); }