git-async 0.1.1

An async-first library for reading git repositories
Documentation
export class DirectoryWrapper {
  constructor(inner) {
    this.inner = inner;
  }

  async openSubdir(name) {
    return new DirectoryWrapper(await this.inner.openSubdir(name));
  }

  listDir() {
    return this.inner.listDir();
  }

  async openFile(name) {
    return new FileWrapper(await this.inner.openFile(name));
  }
}

export class FileWrapper {
  constructor(inner) {
    this.inner = inner;
  }

  readAll() {
    return this.inner.readAll();
  }

  readSegment(offset, length) {
    return this.inner.readSegment(offset, length);
  }
}

export class FSFile {
  constructor(file) {
    this.file = file;
  }

  async readAll() {
    const ab = await this.file.arrayBuffer();
    return new Uint8Array(ab);
  }

  async readSegment(offset, length) {
    const sliced = this.file.slice(offset, offset + length);
    const ab = await sliced.arrayBuffer();
    return new Uint8Array(ab);
  }
}

export class FSDirectory {
  constructor(handle) {
    this.handle = handle;
  }

  async openSubdir(name) {
    const handle = await this.handle.getDirectoryHandle(name);
    return new FSDirectory(handle);
  }

  async listDir() {
    const entries = await collect(this.handle.entries());
    const directories = entries
      .filter(([, handle]) => handle.kind === "directory")
      .map(([name]) => name);
    const files = entries.filter(([, handle]) => handle.kind === "file").map(([name]) => name);
    return [directories, files];
  }

  async openFile(name) {
    const handle = await this.handle.getFileHandle(name);
    const file = await handle.getFile();
    return new FSFile(file);
  }
}

export function entriesDirectoryFromFileList(fileList) {
  const first = fileList[0];
  if (first === undefined) {
    throw new Error("empty directory tree");
  }
  const rootName = first.webkitRelativePath.split("/")[0];
  const filesArray = Array.from(fileList);
  return new EntriesDirectory(filesArray, rootName + "/");
}

export class EntriesDirectory {
  constructor(files, subPath) {
    this.files = files;
    this.subPath = subPath;
  }

  async openSubdir(name) {
    const targetPath = this.subPath + name + "/";
    return new EntriesDirectory(
      this.files.filter((file) => file.webkitRelativePath.startsWith(targetPath)),
      targetPath,
    );
  }

  async listDir() {
    const subFiles = this.files.filter((file) => file.webkitRelativePath.startsWith(this.subPath));
    const directories = new Set();
    const files = [];
    for (const subFile of subFiles) {
      const relPath = subFile.webkitRelativePath.slice(this.subPath.length);
      const [firstComponent, ...rest] = relPath.split("/");
      if (firstComponent === undefined) {
        continue;
      }
      if (rest.length !== 0) {
        directories.add(firstComponent);
      } else {
        files.push(firstComponent);
      }
    }
    return [Array.from(directories), files];
  }

  async openFile(name) {
    const targetPath = this.subPath + name;
    const file = this.files.find((file) => file.webkitRelativePath === targetPath);
    if (file === undefined) {
      throw "file not found";
    }
    return new FSFile(file);
  }
}

async function collect(iter) {
  const out = [];
  for await (const item of iter) {
    out.push(item);
  }
  return out;
}