forked from tools/josh
1
0
Fork 0

Perform simple conversion to TypeScript

This commit is contained in:
Florine W. Dekker 2019-10-20 23:55:04 +02:00
parent d805d0fbe5
commit c6b59daf42
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
10 changed files with 180 additions and 94 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Output
build/*

View File

@ -27,9 +27,10 @@
</div>
<script src="js/shared.js"></script>
<script src="js/terminal.js"></script>
<script src="js/commands.js"></script>
<script src="js/fs.js"></script>
<script type="module" src="build/extensions.js"></script>
<script type="module" src="build/shared.js"></script>
<script type="module" src="build/terminal.js"></script>
<script type="module" src="build/commands.js"></script>
<script type="module" src="build/fs.js"></script>
</body>
</html>

View File

@ -1,4 +1,14 @@
class Commands {
import "./extensions.js"
import {FileSystem, UrlFile} from "./fs.js"
import {terminal} from "./terminal.js";
export class Commands {
private _terminal: any;
private _fs: any;
private _list: any;
constructor(terminal, fileSystem) {
this._terminal = terminal;
this._fs = fileSystem;
@ -278,6 +288,11 @@ class Commands {
}
class InputArgs {
private _command: any;
private _options: any;
private _args: any;
constructor(input) {
const inputParts = (input.match(/("[^"]+"|[^"\s]+)/g) || [])
.map(it => it.replace(/^"/, "").replace(/"$/, ""));
@ -342,7 +357,7 @@ class InputArgs {
return this._command;
}
getOption(key, def) {
getOption(key, def = undefined) {
return (def === undefined)
? this._options[key]
: this._options[key] || def;

7
js/extensions.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
interface String {
trimLines(): string;
}
interface Array<T> {
sortAlphabetically(transform: (element: T) => string);
}

37
js/extensions.ts Normal file
View File

@ -0,0 +1,37 @@
interface String {
trimLines(): string;
replaceAll(regex: RegExp, replacement: string): string;
}
String.prototype.trimLines = function (): string {
return this.split("\n").map(it => it.trim()).join("\n");
};
String.prototype.replaceAll = function (regex, replacement) {
let string = this;
while (regex.test(string))
string = string.replace(regex, replacement);
return "" + string;
};
interface Array<T> {
sortAlphabetically(transform: (element: T) => string);
}
Array.prototype.sortAlphabetically = function (transform = (x) => x) {
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;
});
};

View File

@ -1,4 +1,13 @@
class FileSystem {
import {emptyFunction} from "./shared.js";
import {relToAbs} from "./terminal.js";
export class FileSystem {
pwd: string;
private _root: Directory;
private files: Directory;
constructor() {
this.pwd = "/";
this._root = new Directory({
@ -123,7 +132,7 @@ class FileSystem {
if (tailNode !== undefined)
return "";
headNode.addNode(path.tail, new File(path.tail));
headNode.addNode(path.tail, new File());
return "";
}
@ -203,7 +212,7 @@ class FileSystem {
const nodes = dir.getNodes();
Object.keys(nodes)
.sortAlphabetically()
.sortAlphabetically((x) => x)
.forEach(name => {
const node = nodes[name];
@ -225,7 +234,7 @@ class FileSystem {
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
*/
mkdir(pathString) {
const path = new Path(pathString);
const path = new Path(pathString, undefined);
const headNode = this._getFile(path.head);
if (headNode === undefined)
@ -261,11 +270,11 @@ class FileSystem {
* @returns {string} an empty string if the move was successful, or a message explaining what went wrong
*/
mv(sourceString, destinationString) {
const sourcePath = new Path(sourceString);
const sourcePath = new Path(sourceString, undefined);
const sourceHeadNode = this._getFile(sourcePath.head);
const sourceTailNode = this._getFile(sourcePath.path);
const destinationPath = new Path(destinationString);
const destinationPath = new Path(destinationString, undefined);
const destinationHeadNode = this._getFile(destinationPath.head);
const destinationTailNode = this._getFile(destinationPath.path);
@ -288,7 +297,7 @@ class FileSystem {
return `The file '${targetName}' already exists`;
sourceHeadNode.removeNode(sourceTailNode);
targetNode.addNode(sourceTailNode);
targetNode.addNode(sourceTailNode, undefined);
sourceTailNode.name = targetName;
return "";
@ -312,7 +321,7 @@ class FileSystem {
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
*/
rm(pathString, force = false, recursive = false, noPreserveRoot = false) {
const path = new Path(pathString);
const path = new Path(pathString, undefined);
const parentNode = this._getFile(path.head);
if (parentNode === undefined)
@ -371,7 +380,7 @@ class FileSystem {
* @returns {string} an empty string if the removal was successful, or a message explaining what went wrong
*/
rmdir(pathString) {
const path = new Path(pathString);
const path = new Path(pathString, undefined);
if (path.path === "/") {
if (this._root.getNodeCount() > 0)
@ -412,7 +421,13 @@ class FileSystem {
}
class Path {
export class Path {
private _path: string;
private _parts: string[];
private _head: string;
private _tail: string;
constructor(currentPath, relativePath) {
let path;
if (relativePath === undefined)
@ -453,7 +468,7 @@ class Path {
}
}
class Node {
export class Node {
copy() {
throw "Cannot execute abstract method!";
}
@ -467,7 +482,12 @@ class Node {
}
}
class Directory extends Node {
export class Directory extends Node {
private _parent: this;
private _nodes: {};
name: string;
constructor(nodes = {}) {
super();
@ -527,7 +547,7 @@ class Directory extends Node {
return `<a href="#" class="dirLink" onclick="run('cd ${relToAbs(name)}/');run('ls');">${name}/</a>`;
}
visit(fun, pre = emptyFunction, post = emptyFunction) {
visit(fun, pre: (dir: Directory) => void = emptyFunction, post: (dir: Directory) => void = emptyFunction) {
pre(this);
fun(this);
@ -539,7 +559,7 @@ class Directory extends Node {
}
}
class File extends Node {
export class File extends Node {
constructor() {
super();
}
@ -553,14 +573,17 @@ class File extends Node {
return name;
}
visit(fun, pre = emptyFunction, post = emptyFunction) {
visit(fun, pre: (dir: File) => void = emptyFunction, post: (dir: File) => void = emptyFunction) {
pre(this);
fun(this);
post(this);
}
}
class UrlFile extends File {
export class UrlFile extends File {
url: any;
constructor(url) {
super();

View File

@ -1,66 +0,0 @@
const asciiHeader = `&nbsp;________ _______ _ _
| ____\\ \\ / / __ \\ | | | |
| |__ \\ \\ /\\ / /| | | | ___| | _| | _____ _ __
| __| \\ \\/ \\/ / | | | |/ _ \\ |/ / |/ / _ \\ '__|
| | \\ /\\ / | |__| | __/ <| < __/ |
|_| \\/ \\/ |_____/ \\___|_|\\_\\_|\\_\\___|_| `;
const asciiHeaderHtml = `<span class="wideScreenOnly">${asciiHeader}</span><span class="smallScreenOnly"><b><u>FWDekker</u></b></span>`;
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;
while (regex.test(string))
string = string.replace(regex, replacement);
return "" + string;
};
String.prototype.trimLines = function () {
return this.split("\n").map(it => it.trim()).join("\n");
};
function addOnLoad(fun) {
const oldOnLoad = window.onload || (() => {
});
window.onload = (() => {
oldOnLoad();
fun();
});
}
function moveCaretToEndOf(element) {
const range = document.createRange();
range.selectNodeContents(element);
range.collapse(false);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
function q(query) {
return document.querySelector(query);
}

36
js/shared.ts Normal file
View File

@ -0,0 +1,36 @@
export const asciiHeader = `&nbsp;________ _______ _ _
| ____\\ \\ / / __ \\ | | | |
| |__ \\ \\ /\\ / /| | | | ___| | _| | _____ _ __
| __| \\ \\/ \\/ / | | | |/ _ \\ |/ / |/ / _ \\ '__|
| | \\ /\\ / | |__| | __/ <| < __/ |
|_| \\/ \\/ |_____/ \\___|_|\\_\\_|\\_\\___|_| `;
export const asciiHeaderHtml = `<span class="wideScreenOnly">${asciiHeader}</span><span class="smallScreenOnly"><b><u>FWDekker</u></b></span>`;
export const emptyFunction = () => {};
export function addOnLoad(fun: () => void) {
const oldOnLoad = window.onload || (() => {
});
window.onload = (() => {
// @ts-ignore TODO Find out how to resolve this
oldOnLoad();
fun();
});
}
export function moveCaretToEndOf(element: Node) {
const range = document.createRange();
range.selectNodeContents(element);
range.collapse(false);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
export function q(query: string) {
return document.querySelector(query);
}

View File

@ -1,4 +1,20 @@
class Terminal {
import {addOnLoad, asciiHeaderHtml, moveCaretToEndOf, q} from "./shared.js";
import {FileSystem} from "./fs.js";
import {Commands} from "./commands.js";
export class Terminal {
private _terminal: any;
private _input: any;
private _output: any;
private _prefixDiv: any;
private _user: string;
private _loggedIn: boolean;
private _inputHistory: InputHistory;
private _fs:FileSystem;
private _commands: Commands;
constructor(terminal, input, output, prefixDiv) {
this._terminal = terminal;
this._input = input;
@ -172,15 +188,20 @@ class Terminal {
}
class InputHistory {
private _history: string[];
private _index: number;
constructor() {
this._history = [];
this._index = -1;
}
addEntry(entry) {
addEntry(entry: string) {
if (entry.trim() !== "")
this._history.unshift(entry);
this._index = -1;
}
@ -214,7 +235,7 @@ class InputHistory {
}
let terminal;
export let terminal;
addOnLoad(() => {
terminal = new Terminal(
@ -227,11 +248,10 @@ addOnLoad(() => {
terminal.processInput("ls");
});
function run(command) {
export function run(command: string) {
terminal.processInput(command);
}
function relToAbs(filename) {
export function relToAbs(filename) {
return terminal._fs.pwd + filename;
}

11
tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"module": "esnext",
"target": "es2019",
"sourceMap": true,
"outDir": "./build"
},
"include": [
"**/*"
]
}