Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | 4x 4x 4x 4x 156x 299x 299x 299x 299x 385x 345x 345x 259x 40x 69x 49x 49x 27x 22x 156x 190x 186x 182x 182x 8x 8x 4x 8x 4x 4x 8x 8x 4x 4x 166x 174x 174x 174x 156x 35x 31x 27x 14x 14x 14x 156x 32x 28x 24x 24x 6x 18x 156x 42x 38x 22x 18x 7x 7x 16x 12x 156x 20x 16x 16x 8x 4x 4x 28x 8x 156x 24x 16x 56x 24x 16x 8x 8x 156x 12x 36x 4x 156x | import type * as crud from '../crud/types'; import type * as fsa from '../fsa/types'; import { assertName } from '../node-to-fsa/util'; import { assertType } from '../crud/util'; import { newExistsError, newFile404Error, newFolder404Error, newMissingError } from './util'; export class FsaCrud implements crud.CrudApi { public constructor( protected readonly root: fsa.IFileSystemDirectoryHandle | Promise<fsa.IFileSystemDirectoryHandle>, ) {} protected async getDir( collection: crud.CrudCollection, create: boolean, ): Promise<[dir: fsa.IFileSystemDirectoryHandle, parent: fsa.IFileSystemDirectoryHandle | undefined]> { let parent: undefined | fsa.IFileSystemDirectoryHandle = undefined; let dir = await this.root; try { for (const name of collection) { const child = await dir.getDirectoryHandle(name, { create }); parent = dir; dir = child; } return [dir, parent]; } catch (error) { if (error.name === 'NotFoundError') throw newFolder404Error(collection); throw error; } } protected async getFile( collection: crud.CrudCollection, id: string, ): Promise<[dir: fsa.IFileSystemDirectoryHandle, file: fsa.IFileSystemFileHandle]> { const [dir] = await this.getDir(collection, false); try { const file = await dir.getFileHandle(id, { create: false }); return [dir, file]; } catch (error) { if (error.name === 'NotFoundError') throw newFile404Error(collection, id); throw error; } } public readonly put = async ( collection: crud.CrudCollection, id: string, data: Uint8Array, options?: crud.CrudPutOptions, ): Promise<void> => { assertType(collection, 'put', 'crudfs'); assertName(id, 'put', 'crudfs'); const [dir] = await this.getDir(collection, true); let file: fsa.IFileSystemFileHandle | undefined; switch (options?.throwIf) { case 'exists': { try { file = await dir.getFileHandle(id, { create: false }); throw newExistsError(); } catch (e) { if (e.name !== 'NotFoundError') throw e; file = await dir.getFileHandle(id, { create: true }); } break; } case 'missing': { try { file = await dir.getFileHandle(id, { create: false }); } catch (e) { if (e.name === 'NotFoundError') throw newMissingError(); throw e; } break; } default: { file = await dir.getFileHandle(id, { create: true }); } } const writable = await file!.createWritable(); await writable.write(data); await writable.close(); }; public readonly get = async (collection: crud.CrudCollection, id: string): Promise<Uint8Array> => { assertType(collection, 'get', 'crudfs'); assertName(id, 'get', 'crudfs'); const [, file] = await this.getFile(collection, id); const blob = await file.getFile(); const buffer = await blob.arrayBuffer(); return new Uint8Array(buffer); }; public readonly del = async (collection: crud.CrudCollection, id: string, silent?: boolean): Promise<void> => { assertType(collection, 'del', 'crudfs'); assertName(id, 'del', 'crudfs'); try { const [dir] = await this.getFile(collection, id); await dir.removeEntry(id, { recursive: false }); } catch (error) { if (!silent) throw error; } }; public readonly info = async (collection: crud.CrudCollection, id?: string): Promise<crud.CrudResourceInfo> => { assertType(collection, 'info', 'crudfs'); if (id) { assertName(id, 'info', 'crudfs'); const [, file] = await this.getFile(collection, id); const blob = await file.getFile(); return { type: 'resource', id, size: blob.size, modified: blob.lastModified, }; } else { await this.getDir(collection, false); return { type: 'collection', id: '', }; } }; public readonly drop = async (collection: crud.CrudCollection, silent?: boolean): Promise<void> => { assertType(collection, 'drop', 'crudfs'); try { const [dir, parent] = await this.getDir(collection, false); if (parent) { await parent.removeEntry(dir.name, { recursive: true }); } else { const root = await this.root; for await (const name of root.keys()) await root.removeEntry(name, { recursive: true }); } } catch (error) { if (!silent) throw error; } }; public readonly scan = async function* ( collection: crud.CrudCollection, ): AsyncIterableIterator<crud.CrudCollectionEntry> { assertType(collection, 'scan', 'crudfs'); const [dir] = await this.getDir(collection, false); for await (const [id, handle] of dir.entries()) { if (handle.kind === 'file') { yield { type: 'resource', id, }; } else if (handle.kind === 'directory') { yield { type: 'collection', id, }; } } }; public readonly list = async (collection: crud.CrudCollection): Promise<crud.CrudCollectionEntry[]> => { const entries: crud.CrudCollectionEntry[] = []; for await (const entry of this.scan(collection)) entries.push(entry); return entries; }; public readonly from = async (collection: crud.CrudCollection): Promise<crud.CrudApi> => { assertType(collection, 'from', 'crudfs'); const [dir] = await this.getDir(collection, true); return new FsaCrud(dir); }; } |