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(); }); }); }