@loom-io/core
Version:
A file system wrapper for Node.js and Bun
120 lines (119 loc) • 3.69 kB
JavaScript
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';
}
}