Skip to content

Commit 11d34a7

Browse files
committed
feat: use getAsFileSystemHandle when available
1 parent fedec3e commit 11d34a7

File tree

4 files changed

+84
-2
lines changed

4 files changed

+84
-2
lines changed

src/file-selector.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,26 @@ it('should throw if DataTransferItem is not a File', done => {
259259
.catch(() => done());
260260
});
261261

262+
it('should use getAsFileSystemHandle when available', async () => {
263+
const name = 'test.json';
264+
const [f, h] = createFileSystemFileHandle(name, {ping: true}, {
265+
type: 'application/json'
266+
});
267+
const evt = dragEvtFromItems([
268+
dataTransferItemWithFsHandle(f, h)
269+
]);
270+
const files = await fromEvent(evt);
271+
expect(files).toHaveLength(1);
272+
expect(files.every(file => file instanceof File)).toBe(true);
273+
274+
const [file] = files as FileWithPath[];
275+
276+
expect(file.name).toBe(f.name);
277+
expect(file.type).toBe(f.type);
278+
expect(file.size).toBe(f.size);
279+
expect(file.lastModified).toBe(f.lastModified);
280+
expect(file.path).toBe(name);
281+
});
262282

263283
function dragEvtFromItems(items: DataTransferItem | DataTransferItem[], type: string = 'drop'): DragEvent {
264284
return {
@@ -330,6 +350,18 @@ function dataTransferItemFromEntry(entry: FileEntry | DirEntry, file?: File): Da
330350
} as any;
331351
}
332352

353+
function dataTransferItemWithFsHandle(file?: File, h?: FileSystemFileHandle): DataTransferItem {
354+
return {
355+
kind: 'file',
356+
getAsFile() {
357+
return file;
358+
},
359+
getAsFileSystemHandle() {
360+
return Promise.resolve(h);
361+
}
362+
} as any;
363+
}
364+
333365
function fileSystemFileEntryFromFile(file: File, err?: any): FileEntry {
334366
return {
335367
isDirectory: false,

src/file-selector.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ function flatten<T>(items: any[]): T[] {
121121
}
122122

123123
function fromDataTransferItem(item: DataTransferItem) {
124+
if (typeof (item as any).getAsFileSystemHandle === 'function') {
125+
return (item as any).getAsFileSystemHandle()
126+
.then(async (h: any) => {
127+
const file = await h.getFile();
128+
file.handle = h;
129+
return toFileWithPath(file);
130+
});
131+
}
124132
const file = item.getAsFile();
125133
if (!file) {
126134
return Promise.reject(`${item} is not a File`);

src/file.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,38 @@ describe('toFile()', () => {
123123

124124
reader.readAsText(fileWithPath);
125125
});
126+
127+
it('sets the {handle} if provided', () => {
128+
const path = '/test/test.json';
129+
const file = new File([], 'test.json');
130+
const fileWithHandle = toFileWithPath(file, path, fsHandleFromFile(file));
131+
expect(fileWithHandle.handle).toBeDefined();
132+
expect(fileWithHandle.handle?.name).toEqual(file.name);
133+
});
134+
135+
test('{handle} is enumerable', () => {
136+
const path = '/test/test.json';
137+
const file = new File([], 'test.json');
138+
const fileWithHandle = toFileWithPath(file, path, fsHandleFromFile(file));
139+
140+
expect(Object.keys(fileWithHandle)).toContain('handle');
141+
142+
const keys: string[] = [];
143+
for (const key in fileWithHandle) {
144+
keys.push(key);
145+
}
146+
147+
expect(keys).toContain('handle');
148+
});
149+
126150
});
151+
152+
function fsHandleFromFile(f: File): FileSystemHandle {
153+
return {
154+
kind: 'file',
155+
name: f.name,
156+
isSameEntry() {
157+
return Promise.resolve(false)
158+
}
159+
}
160+
}

src/file.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,7 @@ export const COMMON_MIME_TYPES = new Map([
12011201
]);
12021202

12031203

1204-
export function toFileWithPath(file: FileWithPath, path?: string): FileWithPath {
1204+
export function toFileWithPath(file: FileWithPath, path?: string, h?: FileSystemHandle): FileWithPath {
12051205
const f = withMimeType(file);
12061206
if (typeof f.path !== 'string') { // on electron, path is already set to the absolute path
12071207
const {webkitRelativePath} = file;
@@ -1219,12 +1219,20 @@ export function toFileWithPath(file: FileWithPath, path?: string): FileWithPath
12191219
enumerable: true
12201220
});
12211221
}
1222-
1222+
if (h !== undefined) {
1223+
Object.defineProperty(f, 'handle', {
1224+
value: h,
1225+
writable: false,
1226+
configurable: false,
1227+
enumerable: true
1228+
});
1229+
}
12231230
return f;
12241231
}
12251232

12261233
export interface FileWithPath extends File {
12271234
readonly path?: string;
1235+
readonly handle?: FileSystemFileHandle;
12281236
}
12291237

12301238
function withMimeType(file: FileWithPath) {

0 commit comments

Comments
 (0)