Restructure files

This commit is contained in:
aet
2021-11-11 23:56:06 -05:00
parent b4b21561ed
commit bdd46a530c
29 changed files with 271 additions and 179 deletions

View File

@ -0,0 +1,6 @@
{
"name": "opvault-adapters",
"dependencies": {
"opvault.js": "*"
}
}

View File

@ -0,0 +1,117 @@
import { Buffer } from "buffer"
import type { IAdapter, IFileSystem } from "opvault.js/src/adapter"
function normalize(path: string) {
return path.replace(/^\//, "")
}
function splitPath(path: string) {
const segments = normalize(path).split("/")
const filename = segments.pop()!
return [segments, filename] as const
}
export class FileSystem implements IFileSystem {
constructor(private handle: FileSystemDirectoryHandle) {}
private async getDirectoryHandle(segments: string[]) {
if (!segments.length || (segments.length === 1 && !segments[0])) {
return this.handle
}
const [first, ...pathSegments] = segments
const handle = await pathSegments.reduce(
async (accum, next) => (await accum).getDirectoryHandle(next),
this.handle.getDirectoryHandle(first)
)
return handle
}
private async getFileHandle(path: string) {
const [segments, filename] = splitPath(path)
const dirHandle = await this.getDirectoryHandle(segments)
const fileHandle = await dirHandle.getFileHandle(filename)
return fileHandle
}
async readFile(path: string) {
const handle = await this.getFileHandle(path)
const file = await handle.getFile()
return file.text()
}
async exists(path: string): Promise<boolean> {
if (path === "/") {
return true
}
const [segments, filename] = splitPath(path)
let { handle } = this
for (const segment of segments) {
try {
handle = await handle.getDirectoryHandle(segment)
} catch {
return false
}
}
return (
(await success(() => handle.getFileHandle(filename))) ||
(await success(() => handle.getDirectoryHandle(filename)))
)
}
async readBuffer(path: string): Promise<Buffer> {
const handle = await this.getFileHandle(path)
const file = await handle.getFile()
return Buffer.from(await file.arrayBuffer())
}
async writeFile(path: string, data: string): Promise<void> {
const handle = await this.getFileHandle(path)
const writable = await handle.createWritable()
await writable.write(data)
await writable.close()
}
async readdir(path: string): Promise<string[]> {
const segments = normalize(path).split("/")
const dirHandle = await this.getDirectoryHandle(segments)
const keys: string[] = []
for await (const key of dirHandle.keys()) {
keys.push(key)
}
return keys
}
async isDirectory(path: string) {
const [segments, filename] = splitPath(path)
const dirHandle = await this.getDirectoryHandle(segments)
for await (const [key, handle] of dirHandle.entries()) {
if (key !== filename) continue
if (handle instanceof FileSystemDirectoryHandle) {
return true
} else {
return false
}
}
return false
}
}
async function success(fn: () => Promise<any>) {
try {
await fn()
return true
} catch {
return false
}
}
/**
* Default Browser adapter.
*/
export const getBrowserAdapter = (handle: FileSystemDirectoryHandle): IAdapter => ({
fs: new FileSystem(handle),
subtle: crypto.subtle,
})

View File

@ -0,0 +1,53 @@
import { Buffer } from "buffer"
import type { IAdapter, IFileSystem } from "opvault.js/src/adapter"
export class FileSystem implements IFileSystem {
private paths = new Set<string>()
private pathMap = new Map<string, File>()
constructor(list: FileList) {
for (const file of list) {
this.pathMap.set(file.webkitRelativePath, file)
this.paths.add(file.webkitRelativePath)
}
}
async readFile(path: string) {
return this.pathMap.get(path)!.text()
}
async exists(path: string): Promise<boolean> {
return this.pathMap.has(path)
}
async readBuffer(path: string): Promise<Buffer> {
const arrayBuffer = await this.pathMap.get(path)!.arrayBuffer()
return Buffer.from(arrayBuffer)
}
// eslint-disable-next-line class-methods-use-this
async writeFile(path: string, data: string): Promise<void> {
throw new Error("fs.writeFile is not supported with webkitdirectory")
}
async readdir(path: string): Promise<string[]> {
const paths = [...this.paths]
return paths
.filter(_ => _.startsWith(`${path}/`))
.map(_ => _.slice(path.length + 1))
.map(_ => _.split("/")[0])
}
async isDirectory(path: string) {
const paths = [...this.paths]
return paths.some(_ => _.startsWith(`${path}/`)) && !paths.includes(path)
}
}
/**
* Default Browser adapter.
*/
export const getBrowserAdapter = (list: FileList): IAdapter => ({
fs: new FileSystem(list),
subtle: crypto.subtle,
})