Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/file-selector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,26 @@ it('should throw if DataTransferItem is not a File', done => {
.catch(() => done());
});

it('should use getAsFileSystemHandle when available', async () => {
const name = 'test.json';
const [f, h] = createFileSystemFileHandle(name, {ping: true}, {
type: 'application/json'
});
const evt = dragEvtFromItems([
dataTransferItemWithFsHandle(f, h)
]);
const files = await fromEvent(evt);
expect(files).toHaveLength(1);
expect(files.every(file => file instanceof File)).toBe(true);

const [file] = files as FileWithPath[];

expect(file.name).toBe(f.name);
expect(file.type).toBe(f.type);
expect(file.size).toBe(f.size);
expect(file.lastModified).toBe(f.lastModified);
expect(file.path).toBe(name);
});

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

function dataTransferItemWithFsHandle(file?: File, h?: FileSystemFileHandle): DataTransferItem {
return {
kind: 'file',
getAsFile() {
return file;
},
getAsFileSystemHandle() {
return Promise.resolve(h);
}
} as any;
}

function fileSystemFileEntryFromFile(file: File, err?: any): FileEntry {
return {
isDirectory: false,
Expand Down
8 changes: 8 additions & 0 deletions src/file-selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ function flatten<T>(items: any[]): T[] {
}

function fromDataTransferItem(item: DataTransferItem) {
if (typeof (item as any).getAsFileSystemHandle === 'function') {
return (item as any).getAsFileSystemHandle()
.then(async (h: any) => {
const file = await h.getFile();
file.handle = h;
return toFileWithPath(file);
});
}
const file = item.getAsFile();
if (!file) {
return Promise.reject(`${item} is not a File`);
Expand Down
38 changes: 36 additions & 2 deletions src/file.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('toFile()', () => {

expect(Object.keys(fileWithPath)).toContain('path');

const keys = [];
const keys: string[] = [];
for (const key in fileWithPath) {
keys.push(key);
}
Expand Down Expand Up @@ -83,7 +83,7 @@ describe('toFile()', () => {

expect(Object.keys(fileWithPath)).toContain('type');

const keys = [];
const keys: string[] = [];
for (const key in fileWithPath) {
keys.push(key);
}
Expand Down Expand Up @@ -123,4 +123,38 @@ describe('toFile()', () => {

reader.readAsText(fileWithPath);
});

it('sets the {handle} if provided', () => {
const path = '/test/test.json';
const file = new File([], 'test.json');
const fileWithHandle = toFileWithPath(file, path, fsHandleFromFile(file));
expect(fileWithHandle.handle).toBeDefined();
expect(fileWithHandle.handle?.name).toEqual(file.name);
});

test('{handle} is enumerable', () => {
const path = '/test/test.json';
const file = new File([], 'test.json');
const fileWithHandle = toFileWithPath(file, path, fsHandleFromFile(file));

expect(Object.keys(fileWithHandle)).toContain('handle');

const keys: string[] = [];
for (const key in fileWithHandle) {
keys.push(key);
}

expect(keys).toContain('handle');
});

});

function fsHandleFromFile(f: File): FileSystemHandle {
return {
kind: 'file',
name: f.name,
isSameEntry() {
return Promise.resolve(false)
}
}
}
12 changes: 10 additions & 2 deletions src/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,7 @@ export const COMMON_MIME_TYPES = new Map([
]);


export function toFileWithPath(file: FileWithPath, path?: string): FileWithPath {
export function toFileWithPath(file: FileWithPath, path?: string, h?: FileSystemHandle): FileWithPath {
const f = withMimeType(file);
if (typeof f.path !== 'string') { // on electron, path is already set to the absolute path
const {webkitRelativePath} = file;
Expand All @@ -1219,12 +1219,20 @@ export function toFileWithPath(file: FileWithPath, path?: string): FileWithPath
enumerable: true
});
}

if (h !== undefined) {
Object.defineProperty(f, 'handle', {
value: h,
writable: false,
configurable: false,
enumerable: true
});
}
return f;
}

export interface FileWithPath extends File {
readonly path?: string;
readonly handle?: FileSystemFileHandle;
}

function withMimeType(file: FileWithPath) {
Expand Down
Loading