async rename()

in packages/web-ide-fs/src/browserfs/OverlayFSImpl.ts [191:257]


  async rename(oldPath: string, newPath: string): Promise<void> {
    // Original impl https://github.com/jvilk/BrowserFS/blob/v1.4.3/src/backend/OverlayFS.ts#L178
    // See "Write Strategy" and "Delete Strategy" in class description
    this.#throwIfProtectedPath(oldPath);
    this.#throwIfProtectedPath(newPath);

    const oldExistsInWritable = await this.#existsInWritable(oldPath);
    const oldExistsInReadable = await this.#existsInReadable(oldPath);
    const oldExists = oldExistsInReadable || oldExistsInWritable;

    if (!oldExists) {
      throw ApiError.ENOENT(oldPath);
    }
    if (oldPath === newPath) {
      return;
    }
    if (await this.exists(newPath)) {
      throw ApiError.EEXIST(newPath);
    }

    // what: Optimistically prep newPath directory in writable FS
    // why: Without this we could run into errors renaming oldPath to newPath
    await mkdirp(this.#writable, dirname(newPath));

    const stat = await this.stat(oldPath, false);

    if (stat.isFile()) {
      // condition: isFile and already exist in writable
      // then: we can simply rename
      if (oldExistsInWritable) {
        await this.#writable.rename(oldPath, newPath);
      }
      // condition: isFile and exist **only** in readable
      // then: we have to write the readable content into writable
      else {
        const content = await this.#readable.readFile(oldPath, null, FileFlag.getFileFlag('r'));

        await this.#writable.writeFile(
          newPath,
          content,
          null,
          FileFlag.getFileFlag('w'),
          makeModeWritable(stat.mode),
        );
      }

      // what: Add deleted record if oldPath exists in readable
      if (oldExistsInReadable) {
        await this.#deletedFiles.append('file', oldPath);
      }

      return;
    }

    // condition: oldPath isDirectory and exists in readable
    // then: we need to move any missing children over to writable
    if (oldExistsInReadable) {
      await this.#copyFromReadableToWritable(oldPath, { includeChildren: true });
    }

    await this.#writable.rename(oldPath, newPath);

    // what: Add deleted record if oldPath exists in readable
    if (oldExistsInReadable) {
      await this.#deletedFiles.append('dir', oldPath);
    }
  }