forked from tools/josh
1
0
Fork 0

Enable strict type checking

This commit is contained in:
Florine W. Dekker 2019-10-21 17:07:16 +02:00
parent c736981c20
commit 511b1a1e24
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
7 changed files with 55 additions and 30 deletions

View File

@ -6,7 +6,7 @@ import {Terminal} from "./terminal.js";
export class Commands {
private readonly terminal: Terminal;
private readonly fileSystem: FileSystem;
private readonly commands: object;
private readonly commands: { [key: string]: Command };
constructor(terminal: Terminal, fileSystem: FileSystem) {
@ -134,7 +134,7 @@ export class Commands {
}
parse(input: string): string {
execute(input: string): string {
const args = new InputArgs(input);
if (args.command.trim() === "")
@ -296,7 +296,7 @@ class Command {
class InputArgs {
readonly command: string;
private readonly _options: object;
private readonly _options: { [key: string]: string };
private readonly _args: string[];
@ -353,7 +353,7 @@ class InputArgs {
}
getArg(index: number, def: string = undefined): string {
getArg(index: number, def: string | undefined = undefined): string {
return (def === undefined)
? this._args[index]
: (this.hasArg(index) ? this._args[index] : def);
@ -364,7 +364,7 @@ class InputArgs {
}
getOption(key: string, def: string = undefined) {
getOption(key: string, def: string | undefined = undefined) {
return (def === undefined)
? this._options[key]
: (this.hasOption(key) ? this._options[key] : def);

2
js/extensions.d.ts vendored
View File

@ -3,5 +3,5 @@ interface String {
}
interface Array<T> {
sortAlphabetically(transform: (element: T) => string);
sortAlphabetically(transform: (element: T) => string): T[];
}

View File

@ -9,7 +9,7 @@ String.prototype.trimLines = function (): string {
};
String.prototype.replaceAll = function (regex, replacement) {
let string = this;
let string = this.toString();
while (regex.test(string))
string = string.replace(regex, replacement);
@ -19,10 +19,10 @@ String.prototype.replaceAll = function (regex, replacement) {
interface Array<T> {
sortAlphabetically(transform: (element: T) => string);
sortAlphabetically(transform: (element: T) => string): T[];
}
Array.prototype.sortAlphabetically = function (transform = (x) => x) {
Array.prototype.sortAlphabetically = function (transform: (_: any) => string = (it) => it) {
return this.sort((a, b) => {
const aName = transform(a).toLowerCase();
const bName = transform(b).toLowerCase();

View File

@ -28,6 +28,7 @@ export class FileSystem {
}),
"resume.pdf": new UrlFile("https://static.fwdekker.com/misc/resume.pdf")
});
this.files = this.root;
}
@ -62,8 +63,8 @@ export class FileSystem {
}
private executeForEach(inputs: string[], fun: (string) => string): string {
const outputs = [];
private executeForEach(inputs: string[], fun: (_: string) => string): string {
const outputs: string[] = [];
inputs.forEach(input => {
const output = fun(input);
@ -161,9 +162,15 @@ export class FileSystem {
let targetNode;
let targetName;
if (destinationTailNode === undefined) {
if (!(destinationHeadNode instanceof Directory))
return `The path '${destinationPath.head}' does not point to a directory`;
targetNode = destinationHeadNode;
targetName = destinationPath.tail;
} else {
if (!(destinationTailNode instanceof Directory))
return `The path '${destinationPath.tail}' does not point to a directory`;
targetNode = destinationTailNode;
targetName = sourcePath.tail;
}
@ -192,7 +199,7 @@ export class FileSystem {
return `'${path.path}' is not a directory`;
const dirList = [new Directory({}).nameString("."), new Directory({}).nameString("..")];
const fileList = [];
const fileList: string[] = [];
const nodes = node.nodes;
Object.keys(nodes)
@ -272,9 +279,15 @@ export class FileSystem {
let targetNode;
let targetName;
if (destinationTailNode === undefined) {
if (!(destinationHeadNode instanceof Directory))
return `The path '${destinationPath.head}' does not point to a directory`;
targetNode = destinationHeadNode;
targetName = destinationPath.tail;
} else {
if (!(destinationTailNode instanceof Directory))
return `The path '${destinationPath.tail}' does not point to a directory`;
targetNode = destinationTailNode;
targetName = sourcePath.tail;
}
@ -403,7 +416,7 @@ export class Path {
readonly tail: string;
constructor(currentPath: string, relativePath: string = undefined) {
constructor(currentPath: string, relativePath: string | undefined = undefined) {
let path;
if (relativePath === undefined)
path = currentPath;
@ -435,26 +448,29 @@ export abstract class Node {
abstract nameString(name: string): string;
abstract visit(fun: (node: Node) => void, pre: (node: Node) => void, post: (node: Node) => void);
abstract visit(fun: (node: Node) => void, pre: (node: Node) => void, post: (node: Node) => void): void;
}
export class Directory extends Node {
private readonly _nodes: object;
private readonly _nodes: { [key: string]: Node };
// noinspection TypeScriptFieldCanBeMadeReadonly: False positive
private _parent: Directory;
constructor(nodes: object = {}) {
constructor(nodes: { [key: string]: Node } = {}) {
super();
this._parent = this;
this._nodes = nodes;
Object.keys(this._nodes).forEach(name => this._nodes[name]._parent = this);
Object.values(this._nodes)
.forEach(node => {
if (node instanceof Directory) node._parent = this;
});
}
get nodes(): object {
get nodes(): { [key: string]: Node } {
return Object.assign({}, this._nodes);
}
@ -488,6 +504,9 @@ export class Directory extends Node {
removeNode(nodeOrName: Node | string) {
if (nodeOrName instanceof Node) {
const name = Object.keys(this._nodes).find(key => this._nodes[key] === nodeOrName);
if (name === undefined)
throw `Could not remove node '${nodeOrName}'.`;
delete this._nodes[name];
} else {
delete this._nodes[name];
@ -496,9 +515,7 @@ export class Directory extends Node {
copy(): Directory {
const copy = new Directory(this.nodes);
copy._parent = undefined;
return copy;
return new Directory(this.nodes);
}
nameString(name: string): string {

View File

@ -26,10 +26,16 @@ export function moveCaretToEndOf(element: Node) {
range.collapse(false);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
if (selection !== null) {
selection.removeAllRanges();
selection.addRange(range);
}
}
export function q(query: string): HTMLElement {
return document.querySelector(query);
const element = document.querySelector(query);
if (!(element instanceof HTMLElement))
throw "Could not find element `query`.";
return element;
}

View File

@ -13,7 +13,7 @@ export class Terminal {
private readonly fileSystem: FileSystem;
private readonly commands: Commands;
private _currentUser: string;
private _currentUser: string | undefined;
private isLoggedIn: boolean;
@ -64,7 +64,7 @@ export class Terminal {
this.prefixDiv.innerHTML = prefixText;
}
get currentUser(): string {
get currentUser(): string | undefined {
return this._currentUser;
}
@ -149,7 +149,7 @@ export class Terminal {
this.outputText += `${this.prefixText}${input}\n`;
this.inputHistory.addEntry(input);
const output = this.commands.parse(input.trim());
const output = this.commands.execute(input.trim());
if (output !== "")
this.outputText += output + `\n`;
}
@ -162,7 +162,7 @@ export class Terminal {
this.input.focus();
}
private onkeypress(event) {
private onkeypress(event: KeyboardEvent) {
switch (event.key.toLowerCase()) {
case "enter":
this.processInput(this.inputText.replaceAll(/&nbsp;/, " "));
@ -171,7 +171,7 @@ export class Terminal {
}
}
private onkeydown(event) {
private onkeydown(event: KeyboardEvent) {
switch (event.key.toLowerCase()) {
case "arrowup":
this.inputText = this.inputHistory.previousEntry();
@ -200,7 +200,8 @@ class InputHistory {
constructor() {
this.clear();
this.history = [];
this.index = -1;
}

View File

@ -3,6 +3,7 @@
"module": "esnext",
"target": "es2019",
"sourceMap": true,
"strict": true,
"outDir": "./build/js"
},
"files": [