Skip to content

Commit 1a997bd

Browse files
jonkoopsrolandjitsu
authored andcommitted
refactor: clean up file system entry retrieval
Signed-off-by: Jon Koops <[email protected]>
1 parent 34575db commit 1a997bd

File tree

2 files changed

+64
-50
lines changed

2 files changed

+64
-50
lines changed

src/file-selector.spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,22 @@ it("should return an empty array if the passed event is not a DragEvent", async
7575
expect(files).toHaveLength(0);
7676
});
7777

78+
it("should return an empty array if the dragged item not a directory or file", async () => {
79+
const evt = dragEvtFromItems([
80+
dataTransferItemFromEntry(
81+
fileSystemDirEntryFromFile([
82+
{
83+
isDirectory: false,
84+
isFile: false,
85+
} as FileEntry,
86+
]),
87+
),
88+
]);
89+
90+
const files = await fromEvent(evt);
91+
expect(files).toHaveLength(0);
92+
});
93+
7894
it("should return files from DataTransfer {items} if the passed event is a DragEvent", async () => {
7995
const name = "test.json";
8096
const mockFile = createFile(

src/file-selector.ts

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ function toFilePromises(item: DataTransferItem) {
8888
// Safari supports dropping an image node from a different window and can be retrieved using
8989
// the DataTransferItem.getAsFile() API
9090
// NOTE: FileSystemEntry.file() throws if trying to get the file
91-
if (entry && entry.isDirectory) {
92-
return fromDirEntry(entry) as any;
91+
if (entry && isDirectoryEntry(entry)) {
92+
return fromDirectoryEntry(entry);
9393
}
9494

9595
return fromDataTransferItem(item, entry);
@@ -124,64 +124,62 @@ function fromDataTransferItem(
124124
return Promise.resolve(fwp);
125125
}
126126

127-
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry
128-
async function fromEntry(entry: any) {
129-
return entry.isDirectory ? fromDirEntry(entry) : fromFileEntry(entry);
127+
async function fromEntry(
128+
entry: FileSystemEntry,
129+
): Promise<FileWithPath | FileArray[]> {
130+
if (isDirectoryEntry(entry)) {
131+
return fromDirectoryEntry(entry);
132+
} else if (isFileEntry(entry)) {
133+
return fromFileEntry(entry);
134+
}
135+
136+
return [];
130137
}
131138

132-
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry
133-
function fromDirEntry(entry: any) {
139+
async function fromDirectoryEntry(
140+
entry: FileSystemDirectoryEntry,
141+
): Promise<FileArray[]> {
134142
const reader = entry.createReader();
143+
const entries: Promise<FileValue[]>[] = [];
135144

136-
return new Promise<FileArray[]>((resolve, reject) => {
137-
const entries: Promise<FileValue[]>[] = [];
138-
139-
function readEntries() {
140-
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry/createReader
141-
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryReader/readEntries
142-
reader.readEntries(
143-
async (batch: any[]) => {
144-
if (!batch.length) {
145-
// Done reading directory
146-
try {
147-
const files = await Promise.all(entries);
148-
resolve(files);
149-
} catch (err) {
150-
reject(err);
151-
}
152-
} else {
153-
const items = Promise.all(batch.map(fromEntry));
154-
entries.push(items);
155-
156-
// Continue reading
157-
readEntries();
158-
}
159-
},
160-
(err: any) => {
161-
reject(err);
162-
},
163-
);
145+
while (true) {
146+
const batch = await readEntries(reader);
147+
148+
if (!batch.length) {
149+
break;
164150
}
165151

166-
readEntries();
167-
});
152+
entries.push(Promise.all(batch.map(fromEntry)));
153+
}
154+
155+
const files = await Promise.all(entries);
156+
return files;
168157
}
169158

170-
// https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileEntry
171-
async function fromFileEntry(entry: any) {
172-
return new Promise<FileWithPath>((resolve, reject) => {
173-
entry.file(
174-
(file: FileWithPath) => {
175-
const fwp = toFileWithPath(file, entry.fullPath);
176-
resolve(fwp);
177-
},
178-
(err: any) => {
179-
reject(err);
180-
},
181-
);
182-
});
159+
async function fromFileEntry(
160+
entry: FileSystemFileEntry,
161+
): Promise<FileWithPath> {
162+
const file = await getFile(entry);
163+
const fileWithPath = toFileWithPath(file, entry.fullPath);
164+
165+
return fileWithPath;
183166
}
184167

168+
const isDirectoryEntry = (
169+
entry: FileSystemEntry,
170+
): entry is FileSystemDirectoryEntry => entry.isDirectory;
171+
172+
const isFileEntry = (entry: FileSystemEntry): entry is FileSystemFileEntry =>
173+
entry.isFile;
174+
175+
const getFile = (entry: FileSystemFileEntry): Promise<File> =>
176+
new Promise((resolve, reject) => entry.file(resolve, reject));
177+
178+
const readEntries = (
179+
reader: FileSystemDirectoryReader,
180+
): Promise<FileSystemEntry[]> =>
181+
new Promise((resolve, reject) => reader.readEntries(resolve, reject));
182+
185183
// Infinite type recursion
186184
// https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540
187185
interface FileArray extends Array<FileValue> {}

0 commit comments

Comments
 (0)