UNPKG

@loom-io/core

Version:

A file system wrapper for Node.js and Bun

120 lines (119 loc) 3.69 kB
import { join as joinPath, normalize, relative as relativePath, sep } from 'node:path'; import { LoomFile } from './file.js'; import { List } from './list.js'; import { DirectoryNotEmptyException, EXCEPTION_REF, isInstanceOfLoomException } from '../exceptions.js'; import { removeTailingSlash } from '@loom-io/common'; export class Directory { _path; _adapter; _strict = false; isRoot; constructor(adapter, path, ...paths) { this._path = joinPath(path, ...(paths || [])); this._adapter = adapter; this.isRoot = this._path === '' || this._path === sep; } strict(strictMode = true) { this._strict = strictMode; return this; } get path() { return this._path; } get name() { if (this.isRoot) { return ''; } const split = removeTailingSlash(this.path).split(sep); return split.pop(); } get parent() { if (this.isRoot) return undefined; const split = this.path.split(sep); split.pop(); return new Directory(this._adapter, normalize(`/${split.join('/')}`)); } get adapter() { return this._adapter; } async exists() { return await this._adapter.dirExists(this.path); } async create() { await this._adapter.mkdir(this.path); } async copyTo(target) { if (target.adapter.isCopyable(this.adapter)) { const targetSub = await target.subDir(this.name); await targetSub.create(); const list = await this.list(); for (const element of list) { if (target instanceof Directory) { await element.copyTo(targetSub); } else { await element.copyTo(targetSub); } } } else { throw new Error('Coping between different adapters is currently not supported'); } } async delete(recursive = false) { try { await this._adapter.rmdir(this.path, { recursive }); } catch (err) { if (isInstanceOfLoomException(err, EXCEPTION_REF.DIRECTORY_NOT_EMPTY)) { throw new DirectoryNotEmptyException(this.path); } else if (this._strict) { throw err; } } } subDir(name) { return new Directory(this._adapter, this.path, normalize(name)); } async list() { const paths = await this._adapter.readdir(this.path); return new List(this, paths); } /** * Returns the relative path to the given path or undefined if the given dir or file is parent or not related */ relativePath(dir) { const p = relativePath(this.path, dir.path); return p === '' ? undefined : p; } file(name) { return new LoomFile(this._adapter, this, normalize(name)); } async filesRecursion(list) { const dirList = list.only('dirs'); let fileList = list.only('files'); for (const el of dirList) { const subList = await el.list(); fileList = fileList.concat(await this.filesRecursion(subList)); } return fileList; } async files(recursive = false) { const list = await this.list(); if (recursive) { return this.filesRecursion(list); } else { const fileList = list.only('files'); return fileList; } } [Symbol.toPrimitive]() { return this.path; } get [Symbol.toStringTag]() { return 'LoomDirectory'; } }