Skip to content

Commit

Permalink
Restructure dir, file and add a list class (#5)
Browse files Browse the repository at this point in the history
* implement a list class to handle list returns and add new functions

* write, fix and extend test and fix code

* update package-lock.json
  • Loading branch information
CordlessWool authored Jan 14, 2024
1 parent ed39004 commit 7dbed5d
Show file tree
Hide file tree
Showing 14 changed files with 778 additions and 295 deletions.
213 changes: 100 additions & 113 deletions package-lock.json

Large diffs are not rendered by default.

125 changes: 60 additions & 65 deletions src/core/dir.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@ import { describe, test, expect, beforeEach, afterEach } from 'vitest';
import { Directory } from './dir.js';

import { TestFilesystemHelper } from '../../test/helpers/testFilesystemHelper.js';

class DirectoryTest extends Directory {

getPath() {
return this.path;
}
}

import { File } from './file.js';

describe('Test Directory Service', () => {
test('Create Instance and set path', () => {
const path = './test/data';
const dir = new DirectoryTest(path);
const dir = new Directory(path);
expect(dir).toBeInstanceOf(Directory);
expect(dir.getPath()).toBe(path);
expect(dir.path).toBe(path);
});

test('relativePath', () => {
const dir = new Directory('./test/');
const dir2 = new Directory('./test/data');
expect(dir.relativePath(dir2)).toBe('data');
});


Expand All @@ -34,6 +33,7 @@ describe('Test Directory Service', () => {
});



describe('list methode', () => {


Expand All @@ -49,73 +49,51 @@ describe('Test Directory Service', () => {
});

test('list directory' , async () => {
const testDir = await testHelper.createDirs();
const testDir = (await testHelper.createDirs()).includeBasePath().getPaths(1);

const dir = new Directory(testHelper.getBasePath());
const paths = await dir.list(undefined);
for(const t of testDir) {
const split = t.split('/');
const firstPart = split ? split[0] : t;
expect(paths).toContain(firstPart);
const paths = await dir.list();
for(const t of paths) {
expect(testDir).toContain((t as Directory).path);
}
});

test('list with subdirectory', async () => {
const subPath = 'someRandomTestDir';
const testSubHelper = testHelper.createSubDir(subPath);
const testDir = await testSubHelper.createDirs(30);
await testHelper.createDirs(2);

const dir = new Directory(testHelper.getBasePath());
const paths = await dir.list(subPath);
for(const t of testDir) {
const split = t.split('/');
const subPart = split ? split[0] : t;
expect(paths).toContain(subPart);
}
});


test('list with additional params', async () => {
await testHelper.createDirs(30);
await testHelper.createDirs(2);

const dir = new Directory(testHelper.getBasePath());
const paths = await dir.list(undefined, 'isDirectory');
expect(paths[0]).toHaveLength(2);
expect(paths[0][0]).toBeTypeOf('string');
expect(paths[0][1]).toBe(true);
});

test('list with additional multiple params', async () => {
await testHelper.createFile('testFile', {path: 'testFile.txt'});

const dir = new Directory(testHelper.getBasePath());
const paths = await dir.list(undefined, 'isDirectory', 'isFile');
expect(paths[0]).toHaveLength(3);
expect(paths[0][0]).toBeTypeOf('string');
expect(paths[0][1]).toBe(false);
expect(paths[0][2]).toBe(true);
});
});

describe('listFiles methode', () => {
const testDir = (await testSubHelper.createDirs(30)).includeBasePath().getPaths(1);
await testHelper.createDirs(7);

test('listFiles test returned amount', async () => {
await testHelper.createDirs();
await testHelper.createFile('lorem', {path: 'testDir234/tt.txt'});
await testHelper.createFile('lorem', {path: 'tt2.txt'});

const dir = new Directory(testHelper.getBasePath());
const files = await dir.listFiles(undefined, true);
expect(files).toHaveLength(2);

const files2 = await dir.listFiles();
expect(files2).toHaveLength(1);
expect(files2[0]).toBe('tt2.txt');

const paths = await dir.subdir(subPath).list();
for(const t of paths) {
expect(testDir).toContain((t as Directory).path);
}
});

// TODO: maybe needed for list.asStringArray();
// test('list with additional params', async () => {
// await testHelper.createDirs(30);
// await testHelper.createDirs(2);

// const dir = new Directory(testHelper.getBasePath());
// const paths = await dir.list(undefined, 'isDirectory');
// expect(paths[0]).toHaveLength(2);
// expect(paths[0][0]).toBeTypeOf('string');
// expect(paths[0][1]).toBe(true);
// });

// test('list with additional multiple params', async () => {
// await testHelper.createFile('testFile', {path: 'testFile.txt'});

// const dir = new Directory(testHelper.getBasePath());
// const paths = await dir.list(undefined, 'isDirectory', 'isFile');
// expect(paths[0]).toHaveLength(3);
// expect(paths[0][0]).toBeTypeOf('string');
// expect(paths[0][1]).toBe(false);
// expect(paths[0][2]).toBe(true);
// });
});

describe('files methode', () => {
Expand All @@ -132,12 +110,29 @@ describe('Test Directory Service', () => {

for(const f of files) {
expect(f).toBeInstanceOf;
expect(await f.text()).toBe('lorem');
expect(await (f as File).text()).toBe('lorem');
}


});

test('get files recursive', async () => {
await testHelper.createDirs();
await testHelper.createFile('lorem', {path: 'dorem/tt.txt'});
await testHelper.createFile('lorem');
await testHelper.createFile('lorem');

const dir = new Directory(testHelper.getBasePath());

const files = await dir.files(true);
expect(files).toHaveLength(3);

for(const f of files) {
expect(f).toBeInstanceOf;
expect(await (f as File).text()).toBe('lorem');
}
});

});


Expand Down
89 changes: 44 additions & 45 deletions src/core/dir.ts
Original file line number Diff line number Diff line change
@@ -1,68 +1,67 @@
import * as fs from 'node:fs/promises';
import type { Dirent } from 'node:fs';
import * as path from 'node:path';
import { File } from './file.js';
import { List } from './list.js';


type PickMatching<T, V> =
{ [K in keyof T as T[K] extends V ? K : never]: T[K] }
type DirentMethodsName = keyof PickMatching<Dirent, () => unknown>;
type ReturnTypeTuble<T extends Array<DirentMethodsName>> = {
[K in keyof T]: ReturnType<Dirent[T[K]]>
}

export class Directory {

constructor(
protected path: string
protected _path: string
) {
fs.access(path);
fs.access(_path);
}

async list(subDir?: string): Promise<string[]>
async list<T extends DirentMethodsName[], U = [string, ...ReturnTypeTuble<T>][]>(subDir?: string, ...params: T): Promise<U>
async list<T extends DirentMethodsName[], U = [string, ...ReturnTypeTuble<T>][]>(subDir?: string, ...params: T): Promise<U | string[]> {
if(params.length === 0) {
const dirs = await fs.readdir(path.join(this.path, subDir ?? ''));
return dirs;
}
get path() {
return this._path;
}

subdir(subDir: string) {
return new Directory(path.join(this.path, subDir));
}

async list(): Promise<List> {

const dirs = await fs.readdir(path.join(this.path, subDir ?? ''), {withFileTypes: true});
const paths = await fs.readdir(this.path, {withFileTypes: true});

return dirs.map((dir: Dirent) => {
const p = params.map((param) => {
return dir[param]();
});
return [dir.name, ...p];
}) as U;

return new List(this, paths);
}

relativePath(dir: Directory): string {
return path.relative(this.path, dir.path);
}


async listFiles(subDir?: string, recursive: boolean = false): Promise<string[]> {
const pathContent = await this.list(subDir, 'isDirectory');
file(name: string) {
return new File(path.join(this.path, name));
}


return await pathContent.reduce<Promise<string[]>>(
async (acc, [name, isDirecotry]) => {
const data = await acc;
if (recursive && isDirecotry) {
const p = path.join(subDir ?? '', name);
const list = await this.listFiles(p, recursive);
const subDirFiles = list.map((subName) => path.join(p, subName));
return data.concat(subDirFiles);
} else if (!isDirecotry) {
data.push(name);
return data;
}
protected async filesRecursion(list: List): Promise<List> {

return data;
}, Promise.resolve(Array<string>())
);
const dirList = list.filterByType('isDirectory');
const fileList = list.filterByType('isFile');

for(const el of dirList) {
if(el instanceof Directory) {
const subList = await el.list();
fileList.add(await this.filesRecursion(subList));
}
}

return fileList;
}

async files(recursive: boolean = false) {
const paths = await this.listFiles('', recursive);
return paths.map((file) => new File(path.join(this.path, file)));
async files(recursive: boolean = false): Promise<List> {
const list = await this.list();

if(recursive) {
return this.filesRecursion(list);
} else {
const fileList = list.filterByType('isFile');
return fileList;
}


}
}
6 changes: 6 additions & 0 deletions src/core/exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,10 @@ export class PluginNotFoundException extends Error {
constructor(path: string) {
super(`No plugin found for ${path}`);
}
}

export class FileConvertException extends Error {
constructor(path: string, message: string) {
super(`Error converting file ${path}: ${message}`);
}
}
Loading

0 comments on commit 7dbed5d

Please sign in to comment.