forked from tools/josh
1
0
Fork 0

Use OOP to represent files and directories

This commit is contained in:
Florine W. Dekker 2018-11-29 12:42:14 +01:00
parent df7401343e
commit 71d5db9587
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
3 changed files with 236 additions and 124 deletions

View File

@ -183,11 +183,11 @@ class Commands {
if (!FileSystem.isFile(file)) {
return `'${fileName} is not a file'`;
}
if (file.type !== "link") {
if (!(file instanceof LinkFile)) {
return `Could not open '${fileName}'`;
}
window.open(file.link, target);
window.open(file.url, target);
return "";
}

336
js/fs.js
View File

@ -1,77 +1,25 @@
class FileSystem {
constructor() {
this._root = {
personal: {
steam: {
type: "link",
link: "https://steamcommunity.com/id/Waflix"
},
nukapedia: {
type: "link",
link: "http://fallout.wikia.com/wiki/User:FDekker"
}
},
projects: {
minor: {
dice: {
type: "link",
link: "https://fwdekker.com/dice"
}
},
randomness: {
type: "link",
link: "https://github.com/FWDekker/intellij-randomness"
},
schaapi: {
type: "link",
link: "http://cafejojo.org/schaapi"
}
},
social: {
github: {
type: "link",
link: "https://github.com/FWDekker/"
},
stackoverflow: {
type: "link",
link: "https://stackoverflow.com/u/3307872"
},
linkedin: {
type: "link",
link: "https://www.linkedin.com/in/fwdekker/"
}
},
"resume.pdf": {
type: "link",
link: "https://fwdekker.com/resume.pdf"
}
};
this.pwd = "/";
const visited = [];
const queue = [this._root];
this._root["."] = this._root;
this._root[".."] = this._root;
while (queue.length !== 0) {
const next = queue.pop();
if (visited.indexOf(next) >= 0) {
continue;
}
visited.push(next);
for (const key in next) {
if (key === "." || key === ".." || FileSystem.isFile(next[key])) {
continue;
}
next[key]["."] = next[key];
next[key][".."] = next;
queue.push(next[key]);
}
}
this._root = new Directory("", undefined, [
new Directory("personal", undefined, [
new LinkFile("steam", "https://steamcommunity.com/id/Waflix"),
new LinkFile("nukapedia", "http://fallout.wikia.com/wiki/User:FDekker")
]),
new Directory("projects", undefined, [
new Directory("minor", undefined, [
new LinkFile("dice", "https://fwdekker.com/dice")
]),
new LinkFile("randomness", "https://github.com/FWDekker/intellij-randomness"),
new LinkFile("schaapi", "http://cafejojo.org/schaapi")
]),
new Directory("social", undefined, [
new LinkFile("github", "https://github.com/FWDekker/"),
new LinkFile("stackoverflow", "https://stackoverflow.com/u/3307872"),
new LinkFile("linkedin", "https://www.linkedin.com/in/fwdekker/")
]),
new LinkFile("resume.pdf", "resume.pdf")
]);
}
@ -115,8 +63,11 @@ class FileSystem {
if (file === undefined) {
return;
}
if (FileSystem.isFile(file)) {
file = undefined;
}
file = file[part];
file = file.getNode(part);
});
return file;
@ -147,23 +98,23 @@ class FileSystem {
/**
* Returns true iff {@code file} represents a directory.
* Returns true iff {@code node} represents a directory.
*
* @param file {Object} an object from the file system
* @returns {boolean} true iff {@code file} represents a directory
* @param node {Object} a node from the file system
* @returns {boolean} true iff {@code node} represents a directory
*/
static isDirectory(file) {
return (file !== undefined && typeof file.type !== "string");
static isDirectory(node) {
return node instanceof Directory;
}
/**
* Returns true iff {@code file} represents a file.
* Returns true iff {@code node} represents a file.
*
* @param file {Object} an object from the file system
* @returns {boolean} true iff {@code file} represents a file
* @param node {Object} an object from the file system
* @returns {boolean} true iff {@code node} represents a file
*/
static isFile(file) {
return (file !== undefined && typeof file.type === "string");
static isFile(node) {
return node instanceof File;
}
@ -179,9 +130,12 @@ class FileSystem {
}
const file = this._getFile(path);
if (file === undefined || !FileSystem.isDirectory(file)) {
if (file === undefined) {
return `The directory '${path}' does not exist`;
}
if (!FileSystem.isDirectory(file)) {
return `'${path}' is not a directory`;
}
this.pwd = this._normalisePath(path);
this.files = file;
@ -198,25 +152,29 @@ class FileSystem {
ls(path) {
path = (path || this.pwd);
const files = this._getFile(path);
if (files === undefined) {
const node = this._getFile(path);
if (node === undefined) {
return `The directory '${path}' does not exist`;
}
if (!FileSystem.isDirectory(node)) {
return `'${path}' is not a directory`;
}
const dirList = [];
const dirList = ["./", "../"];
const fileList = [];
Object.keys(files).sort().forEach(fileName => {
const file = files[fileName];
if (FileSystem.isFile(file)) {
fileList.push(fileToString(fileName, file));
} else if (FileSystem.isDirectory(file)) {
dirList.push(`${fileName}/`);
} else {
throw `${fileName} is neither a file nor a directory!`;
}
});
node.getNodes()
.sortAlphabetically(node => node.name)
.forEach(node => {
if (FileSystem.isDirectory(node)) {
dirList.push(node.toString());
} else if (FileSystem.isFile(node)) {
fileList.push(node.toString());
} else {
throw `${node.name} is neither a file nor a directory!`;
}
}
);
return dirList.concat(fileList).join("\n");
}
@ -232,16 +190,17 @@ class FileSystem {
const childDirName = this._childPath(path);
const parentDir = this._getFile(parentDirName);
if (!FileSystem.isDirectory(parentDir)) {
if (parentDir === undefined) {
return `The directory '${parentDirName}' does not exist`;
}
if (!FileSystem.isDirectory(parentDir)) {
return `'${parentDirName}' is not a directory`;
}
if (parentDir[childDirName] !== undefined) {
return `The directory '${childDirName}' already exists`;
}
parentDir[childDirName] = {};
parentDir[childDirName]["."] = parentDir[childDirName];
parentDir[childDirName][".."] = parentDir;
parentDir.addNode(new Directory(childDirName, parentDir, []));
return "";
}
@ -269,26 +228,36 @@ class FileSystem {
const fileName = this._childPath(path);
const dir = this._getFile(dirName);
if (!FileSystem.isDirectory(dir)) {
if (dir === undefined) {
return force
? ""
: `The directory '${dirName}' does not exist`;
}
if (!FileSystem.isDirectory(dir)) {
return force
? ""
: `'${dirName}' is not a directory`;
}
const file = dir[fileName];
if (!FileSystem.isFile(file)) {
const file = dir.getNode(fileName);
if (file === undefined) {
return force
? ""
: `The file '${fileName}' does not exist`;
}
if (!FileSystem.isFile(file)) {
return force
? ""
: `'${fileName}' is not a file`;
}
delete dir[fileName];
dir.removeNode(file);
return "";
}
rms(paths, force) {
return this._executeForEach(paths, path => {
this.rm(path, force);
return this.rm(path, force);
});
}
@ -303,12 +272,11 @@ class FileSystem {
force = (force || false);
if (this._normalisePath(path) === "/") {
if (!force && Object.keys(this._root).length > 1) {
if (!force && this._root.getNodeCount() > 0) {
return `The directory is not empty.`;
} else {
this._root = {};
this._root["."] = this._root;
return ``;
this._root = new Directory("/", undefined, []);
return "";
}
}
@ -316,23 +284,33 @@ class FileSystem {
const childDirName = this._childPath(path);
const parentDir = this._getFile(parentDirName);
if (!FileSystem.isDirectory(parentDir)) {
if (parentDir === undefined) {
return force
? ""
: `The directory '${parentDirName}' does not exist`;
}
if (!FileSystem.isDirectory(parentDir)) {
return force
? ""
: `'${parentDirName}' is not a directory`;
}
const childDir = parentDir[childDirName];
if (!FileSystem.isDirectory(childDir)) {
const childDir = parentDir.getNode(childDirName);
if (childDir === undefined) {
return force
? ""
: `The directory '${childDirName}' does not exist`;
}
if (!force && Object.keys(childDir).length > 2) {
if (!FileSystem.isDirectory(childDir)) {
return force
? ""
: `'${childDirName}' is not a directory`;
}
if (!force && childDir.getNodeCount() > 0) {
return `The directory is not empty`;
}
delete parentDir[childDirName];
parentDir.removeNode(childDir);
return "";
}
@ -344,11 +322,125 @@ class FileSystem {
}
const fileToString = function (fileName, file) {
switch (file.type) {
case "link":
return `<a href="${file.link}">${fileName}</a>`;
default:
return fileName;
class Node {
constructor(name) {
this.name = name;
}
};
copy() {
throw "Cannot execute abstract method!";
}
toString() {
throw "Cannot execute abstract method!";
}
visit(fun, pre, post) {
throw "Cannot execute abstract method!";
}
}
class Directory extends Node {
constructor(name, parent, nodes) {
super(name);
this._parent = (parent || this);
this._nodes = (nodes || []);
this._nodes.forEach(node => {
node._parent = this;
});
}
getNodes() {
return this._nodes.slice();
}
getNodeCount() {
return this._nodes.length;
}
getNode(name) {
switch (name) {
case ".":
return this;
case "..":
return this._parent;
default:
return this._nodes.find(it => it.name === name);
}
}
addNode(node) {
this._nodes.push(node);
}
removeNode(node) {
const index = this._nodes.indexOf(node);
if (index >= 0) {
this._nodes.splice(index, 1);
return true;
} else {
return false;
}
}
copy() {
return new Directory(this.name, this._parent, this._nodes);
}
toString() {
return `${this.name}/`;
}
visit(fun, pre = emptyFunction, post = emptyFunction) {
pre(this);
fun(this);
this._nodes.forEach(node => node.visit(fun, pre, post));
post(this);
}
}
class File extends Node {
constructor(name) {
super(name);
}
copy() {
return new File(this.name);
}
toString() {
return name;
}
visit(fun, pre = emptyFunction, post = emptyFunction) {
pre(this);
fun(this);
post(this);
}
}
class LinkFile extends File {
constructor(name, url) {
super(name);
this.url = url;
}
copy() {
return new LinkFile(this.name, this.url);
}
toString() {
return `<a href="${this.url}">${this.name}</a>`;
}
}

View File

@ -5,6 +5,26 @@ const asciiHeader = `&nbsp;________ _______ _ _
| | \\ /\\ / | |__| | __/ <| < __/ |
|_| \\/ \\/ |_____/ \\___|_|\\_\\_|\\_\\___|_| `;
const emptyFunction = () => {};
const identityFunction = (x) => x;
Array.prototype.sortAlphabetically = function(transform = identityFunction) {
return this.sort((a, b) => {
const aName = transform(a).toLowerCase();
const bName = transform(b).toLowerCase();
if (aName < bName) {
return -1;
} else if (aName > bName) {
return 1;
} else {
return 0;
}
});
};
String.prototype.replaceAll = function (regex, replacement) {
let string = this;