forked from tools/josh
Fix #43
This commit is contained in:
parent
9bf9ea3810
commit
f5126065bf
|
@ -221,7 +221,6 @@ export class Commands {
|
|||
* Parses and executes the given input string and returns the output generated by that command.
|
||||
*
|
||||
* @param input the input string to parse and execute
|
||||
* @return the output generated by that command
|
||||
*/
|
||||
execute(input: InputArgs): string {
|
||||
if (input.command === "factory-reset") {
|
||||
|
@ -249,7 +248,6 @@ export class Commands {
|
|||
*
|
||||
* @param commandName the name of the command that was used incorrectly
|
||||
* @param errorMessage the message describing how the command was used incorrectly; preferably ended with a `.`
|
||||
* @return an output action corresponding to an error message about invalid usage of a command
|
||||
*/
|
||||
private createUsageErrorOutput(commandName: string, errorMessage: string | undefined): string {
|
||||
const command = this.commands[commandName];
|
||||
|
@ -570,7 +568,6 @@ export class Commands {
|
|||
* Maps sources to inputs for the `move` and `copy` commands.
|
||||
*
|
||||
* @param input the input to extract mappings from
|
||||
* @return the mappings from source to destination
|
||||
*/
|
||||
private moveCopyMappings(input: InputArgs): [Path, Path][] {
|
||||
const sources = input.args.slice(0, -1).map(arg => Path.interpret(this.environment.get("cwd"), arg));
|
||||
|
@ -682,8 +679,6 @@ class InputValidator {
|
|||
* valid.
|
||||
*
|
||||
* @param input the input to validate
|
||||
* @return `[true]` if the input is valid, or `[false, string]` where the string is a reason if the input is not
|
||||
* valid
|
||||
*/
|
||||
validate(input: InputArgs): [true] | [false, string] {
|
||||
if (this.minArgs === this.maxArgs && input.args.length !== this.minArgs)
|
||||
|
@ -700,7 +695,6 @@ class InputValidator {
|
|||
* Returns `"1 argument"` if the given amount is `1` and returns `"$n arguments"` otherwise.
|
||||
*
|
||||
* @param amount the amount to check
|
||||
* @return `"1 argument"` if the given amount is `1` and returns `"$n arguments"` otherwise.
|
||||
*/
|
||||
private args(amount: number): string {
|
||||
return amount === 1 ? `1 argument` : `${amount} arguments`;
|
||||
|
|
|
@ -32,8 +32,6 @@ export class Environment {
|
|||
|
||||
/**
|
||||
* Returns a copy of the variables contained within this environment.
|
||||
*
|
||||
* @return a copy of the variables contained within this environment
|
||||
*/
|
||||
get variables(): { [key: string]: string } {
|
||||
return Object.assign({}, this._variables);
|
||||
|
@ -79,7 +77,6 @@ export class Environment {
|
|||
* environment variable.
|
||||
*
|
||||
* @param key the key of the environment variable to return
|
||||
* @return the value of the environment variable with the given key
|
||||
* @throws if there is no such environment variable
|
||||
*/
|
||||
get(key: string): string {
|
||||
|
@ -94,9 +91,7 @@ export class Environment {
|
|||
* environment variable.
|
||||
*
|
||||
* @param key the key of the environment variable to return
|
||||
* @param def the
|
||||
* @return the value of the environment variable with the given key, or the given default value if there is no such
|
||||
* environment variable
|
||||
* @param def the default value to return in case there is no environment variable with the given key
|
||||
*/
|
||||
getOrDefault(key: string, def: string): string {
|
||||
const value = this._variables[key];
|
||||
|
@ -109,7 +104,6 @@ export class Environment {
|
|||
* Returns `true` if and only if there is an environment variable with the given key.
|
||||
*
|
||||
* @param key the key of the environment variable to check
|
||||
* @return `true` if and only if there is an environment variable with the given key
|
||||
*/
|
||||
has(key: string): boolean {
|
||||
return this._variables.hasOwnProperty(key);
|
||||
|
@ -158,7 +152,6 @@ export class Environment {
|
|||
* Returns `true` if and only if the given key has a valid format.
|
||||
*
|
||||
* @param key the key to validate
|
||||
* @return `true` if and only if the given key has a valid format
|
||||
*/
|
||||
private static isKeyValid(key: string): boolean {
|
||||
return !!key.match(/^[0-9a-z_]+$/i);
|
||||
|
|
|
@ -6,8 +6,6 @@ interface String {
|
|||
|
||||
/**
|
||||
* Returns this string with all leading and trailing whitespace removed from each line.
|
||||
*
|
||||
* @return this string with all leading and trailing whitespace removed from each line
|
||||
*/
|
||||
String.prototype.trimLines = function (): string {
|
||||
return this.split("\n").map(it => it.trim()).join("\n");
|
||||
|
@ -18,7 +16,6 @@ String.prototype.trimLines = function (): string {
|
|||
*
|
||||
* @param regex the regex to find matches with
|
||||
* @param replacement the string to replace matches with
|
||||
* @return this string with all matches with the given regex replaced with the given replacement
|
||||
*/
|
||||
String.prototype.replaceAll = function (regex: RegExp, replacement: string): string {
|
||||
let string = this.toString();
|
||||
|
@ -39,7 +36,6 @@ interface Array<T> {
|
|||
*
|
||||
* @param transform transforms elements of the array into a string that is used for comparing
|
||||
* @param caseSensitive `true` if and only if the comparator should be sensitive to the case of characters
|
||||
* @return a comparator that compares elements of an array based on their string representation
|
||||
*/
|
||||
Array.prototype.sortAlphabetically = function (transform: (_: any) => string = (it) => it,
|
||||
caseSensitive: boolean = true) {
|
||||
|
|
|
@ -94,7 +94,6 @@ export class FileSystem {
|
|||
* Returns the node at the given path, or `undefined` if the node does not exist.
|
||||
*
|
||||
* @param target the path of the node to return
|
||||
* @return the node at the given path, or `undefined` if the node does not exist
|
||||
*/
|
||||
get(target: Path): Node | undefined {
|
||||
if (target.toString() === "/")
|
||||
|
@ -111,7 +110,6 @@ export class FileSystem {
|
|||
* Returns `true` if and only if there exists a node at the given path.
|
||||
*
|
||||
* @param target the path to check for node presence
|
||||
* @return `true` if and only if there exists a node at the given path
|
||||
*/
|
||||
has(target: Path): boolean {
|
||||
if (target.toString() === "/")
|
||||
|
@ -224,7 +222,6 @@ export class Path {
|
|||
*
|
||||
* @param cwd the current working directory, used as a baseline
|
||||
* @param paths the paths that may or may not be absolute
|
||||
* @return an absolute path
|
||||
*/
|
||||
static interpret(cwd: string, ...paths: string[]): Path {
|
||||
if (paths.length === 0)
|
||||
|
@ -238,8 +235,6 @@ export class Path {
|
|||
|
||||
/**
|
||||
* Returns the path describing the parent directory.
|
||||
*
|
||||
* @return the path describing the parent directory
|
||||
*/
|
||||
get parent(): Path {
|
||||
return new Path(this._parent);
|
||||
|
@ -247,8 +242,6 @@ export class Path {
|
|||
|
||||
/**
|
||||
* Returns all ancestors of this path, starting at the parent and ending at the root.
|
||||
*
|
||||
* @return all ancestors of this path, starting at the parent and ending at the root
|
||||
*/
|
||||
get ancestors(): Path[] {
|
||||
const parents: Path[] = [];
|
||||
|
@ -269,7 +262,6 @@ export class Path {
|
|||
* Returns a path describing the path to the desired child node of `this` path.
|
||||
*
|
||||
* @param child the path to the desired node relative to `this` path
|
||||
* @return a path describing the path to the desired child node of `this` path
|
||||
*/
|
||||
getChild(child: string): Path {
|
||||
return new Path(this.path + "/" + child);
|
||||
|
@ -279,7 +271,6 @@ export class Path {
|
|||
* Returns the string representation of this path.
|
||||
*
|
||||
* @param escape `true` if and only if special characters should be escaped for use inside strings
|
||||
* @return the string representation of this path
|
||||
*/
|
||||
toString(escape: boolean = false): string {
|
||||
if (!escape)
|
||||
|
@ -318,15 +309,12 @@ export abstract class Node {
|
|||
*
|
||||
* @param name the name of this node
|
||||
* @param path the path to this node
|
||||
* @return a string representation of this node given the name of and path to this node
|
||||
*/
|
||||
abstract nameString(name: string, path: Path): string;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the JSON serialization of this node.
|
||||
*
|
||||
* @return the JSON serialization of this node
|
||||
*/
|
||||
serialize(): string {
|
||||
return JSON.stringify(this);
|
||||
|
@ -339,7 +327,6 @@ export abstract class Node {
|
|||
* corresponding parse method for that type.
|
||||
*
|
||||
* @param json a JSON string or object describing a node
|
||||
* @return the JSON deserialization of the given string as a node
|
||||
*/
|
||||
static deserialize(json: string | any): Node {
|
||||
if (typeof json === "string") {
|
||||
|
@ -385,8 +372,6 @@ export class Directory extends Node {
|
|||
|
||||
/**
|
||||
* Returns a copy of all nodes contained in this directory.
|
||||
*
|
||||
* @return a copy of all nodes contained in this directory
|
||||
*/
|
||||
get nodes(): { [name: string]: Node } {
|
||||
return Object.assign({}, this._nodes);
|
||||
|
@ -394,8 +379,6 @@ export class Directory extends Node {
|
|||
|
||||
/**
|
||||
* Returns the number of nodes in this directory.
|
||||
*
|
||||
* @return the number of nodes in this directory
|
||||
*/
|
||||
get nodeCount(): number {
|
||||
return Object.keys(this._nodes).length;
|
||||
|
@ -420,8 +403,6 @@ export class Directory extends Node {
|
|||
* directory.
|
||||
*
|
||||
* @param name the name to check
|
||||
* @return `true` if and only if this directory contains a node with the given name or the name refers to this
|
||||
* directory
|
||||
*/
|
||||
hasNode(name: string): boolean {
|
||||
if (name === "." || name === ".." || new Path(`/${name}`).toString() === "/")
|
||||
|
@ -472,7 +453,6 @@ export class Directory extends Node {
|
|||
*
|
||||
* @param name the name of this node
|
||||
* @param path the path to this node
|
||||
* @return a string that contains an HTML hyperlink that runs a command to `cd` to this directory
|
||||
*/
|
||||
nameString(name: string, path: Path): string {
|
||||
return `<a href="#" class="dirLink" onclick="execute('cd ${path.toString(true)}');execute('ls')">${name}</a>`;
|
||||
|
@ -485,7 +465,6 @@ export class Directory extends Node {
|
|||
* The nodes inside the directory of the given object are also recursively parsed by this method.
|
||||
*
|
||||
* @param obj the object that describes a directory
|
||||
* @return the directory described by the given object
|
||||
*/
|
||||
static parse(obj: any): Directory {
|
||||
if (obj["type"] !== "Directory")
|
||||
|
@ -542,7 +521,6 @@ export class File extends Node {
|
|||
* Parses the given object into a file.
|
||||
*
|
||||
* @param obj the object that describes a file
|
||||
* @return the file described by the given object
|
||||
*/
|
||||
static parse(obj: any): File {
|
||||
if (obj["type"] !== "File")
|
||||
|
|
|
@ -42,7 +42,6 @@ export function addOnLoad(fun: () => void): void {
|
|||
* Returns the extension of the given filename, or `""` if it doesn't have one.
|
||||
*
|
||||
* @param filename the filename to return the extension of
|
||||
* @return the extension of the given filename, or `""` if it doesn't have one
|
||||
*/
|
||||
export function getFileExtension(filename: string): string {
|
||||
const extension = /^.+\.([^.]+)$/.exec(filename);
|
||||
|
@ -72,7 +71,6 @@ export function moveCaretToEndOf(node: Node): void {
|
|||
* For example, if the given string is `"3px"`, this function will return `3`.
|
||||
*
|
||||
* @param string the CSS value to extract the number of pixels from
|
||||
* @return the number of pixels in a CSS value that describes a number of pixels, or `0` if the given string is `null`
|
||||
* @throws if the given string does not end with the text `"px"`
|
||||
*/
|
||||
export function parseCssPixels(string: string | null): number {
|
||||
|
@ -90,7 +88,6 @@ export function parseCssPixels(string: string | null): number {
|
|||
* Type-safe shorthand for `document.querySelector(query)`.
|
||||
*
|
||||
* @param query the query to run
|
||||
* @return the same as `document.querySelector(query)`
|
||||
* @throws if the element could not be found
|
||||
*/
|
||||
export function q(query: string): HTMLElement {
|
||||
|
@ -105,7 +102,6 @@ export function q(query: string): HTMLElement {
|
|||
* Returns this string with all HTML tags stripped.
|
||||
*
|
||||
* @param string the string to strip HTML tags from
|
||||
* @return this string with all HTML tags stripped
|
||||
*/
|
||||
export function stripHtmlTags(string: string): string {
|
||||
const div = document.createElement("div");
|
||||
|
|
|
@ -56,9 +56,7 @@ export class Shell {
|
|||
|
||||
|
||||
/**
|
||||
* Generates the header that is displayed when a user logs in.
|
||||
*
|
||||
* @return the header that is displayed when a user logs in
|
||||
* Returns the header that is displayed when a user logs in.
|
||||
*/
|
||||
generateHeader(): string {
|
||||
if (this.environment.get("user") === "")
|
||||
|
@ -77,9 +75,7 @@ export class Shell {
|
|||
}
|
||||
|
||||
/**
|
||||
* Generates the prefix based on the current state of the terminal.
|
||||
*
|
||||
* @return the prefix based on the current state of the terminal
|
||||
* Returns the prefix based on the current state of the terminal.
|
||||
*/
|
||||
generatePrefix(): string {
|
||||
const userName = this.environment.get("user");
|
||||
|
@ -172,7 +168,6 @@ export class Shell {
|
|||
* @param path the path of the file to write or append to
|
||||
* @param data the data to write or append
|
||||
* @param append `true` if and only if the data should be appended
|
||||
* @return an empty string if the writing or appending was successful, or a message explaining what went wrong
|
||||
*/
|
||||
private writeToFile(path: Path, data: string, append: boolean): string {
|
||||
try {
|
||||
|
@ -208,9 +203,6 @@ export class Shell {
|
|||
/**
|
||||
* Returns the file system loaded from a cookie, or the default file system if no cookie is present or the cookie
|
||||
* is invalid.
|
||||
*
|
||||
* @return the file system loaded from a cookie, or the default file system if no cookie is present or the cookie
|
||||
* is invalid
|
||||
*/
|
||||
private static loadFileSystem(): FileSystem {
|
||||
let files: Directory | undefined = undefined;
|
||||
|
@ -235,8 +227,6 @@ export class Shell {
|
|||
*
|
||||
* @param fileSystem the file system used to validate the `cwd` environment variable
|
||||
* @param userList the list of users used to validate the `user` environment variable
|
||||
* @return the environment loaded from a cookie, or the default environment if no cookie is present or the cookie
|
||||
* is invalid
|
||||
*/
|
||||
private static loadEnvironment(fileSystem: FileSystem, userList: UserList): Environment {
|
||||
const environmentString = Cookies.get("env") || "{}";
|
||||
|
@ -325,8 +315,6 @@ export class InputArgs {
|
|||
|
||||
/**
|
||||
* Returns a copy of the options the user has given.
|
||||
*
|
||||
* @return a copy of the options the user has given
|
||||
*/
|
||||
get options(): InputOptions {
|
||||
return Object.assign({}, this._options);
|
||||
|
@ -336,7 +324,6 @@ export class InputArgs {
|
|||
* Returns `true` if and only if the option with the given key has been set.
|
||||
*
|
||||
* @param key the key to check
|
||||
* @return `true` if and only if the option with the given key has been set
|
||||
*/
|
||||
hasOption(key: string): boolean {
|
||||
return this._options.hasOwnProperty(key);
|
||||
|
@ -346,7 +333,6 @@ export class InputArgs {
|
|||
* Returns `true` if and only if at least one of the options with the given keys has been set.
|
||||
*
|
||||
* @param keys the keys to check
|
||||
* @return `true` if and only if at least one of the options with the given keys has been set
|
||||
*/
|
||||
hasAnyOption(keys: string[]): boolean {
|
||||
for (let i = 0; i < keys.length; i++)
|
||||
|
@ -359,8 +345,6 @@ export class InputArgs {
|
|||
|
||||
/**
|
||||
* Returns a copy of the arguments the user has given.
|
||||
*
|
||||
* @return a copy of the arguments the user has given
|
||||
*/
|
||||
get args(): string[] {
|
||||
return this._args.slice();
|
||||
|
@ -370,7 +354,6 @@ export class InputArgs {
|
|||
* Returns `true` if and only if there is an argument at the given index.
|
||||
*
|
||||
* @param index the index to check
|
||||
* @return `true` if and only if there is an argument at the given index
|
||||
*/
|
||||
hasArg(index: number): boolean {
|
||||
return this._args[index] !== undefined;
|
||||
|
@ -401,7 +384,6 @@ export class InputParser {
|
|||
* Parses the given input string to a set of command-line arguments.
|
||||
*
|
||||
* @param input the string to parse
|
||||
* @return the set of parsed command-line arguments
|
||||
*/
|
||||
parse(input: string): InputArgs {
|
||||
const tokens = this.tokenize(input);
|
||||
|
@ -418,7 +400,6 @@ export class InputParser {
|
|||
* Tokenizes the input string.
|
||||
*
|
||||
* @param input the string to tokenize
|
||||
* @return the array of tokens found in the input string
|
||||
*/
|
||||
private tokenize(input: string): string[] {
|
||||
const tokens = [];
|
||||
|
@ -436,7 +417,6 @@ export class InputParser {
|
|||
* Returns the first token in the given string and the remaining string.
|
||||
*
|
||||
* @param input the string of which to return the first token
|
||||
* @return the first token in the given string and the remaining string
|
||||
*/
|
||||
private getNextToken(input: string): [string, string] {
|
||||
let token = "";
|
||||
|
@ -514,7 +494,6 @@ export class InputParser {
|
|||
* Returns the value of the first environment variable in the given string and the length of the variable name.
|
||||
*
|
||||
* @param input the string to find the first environment variable in
|
||||
* @return the value of the first environment variable in the given string and the length of the variable name
|
||||
*/
|
||||
private getNextVariable(input: string): [string, number] {
|
||||
let variable = "";
|
||||
|
@ -534,8 +513,6 @@ export class InputParser {
|
|||
* target if no token describes a redirect target.
|
||||
*
|
||||
* @param tokens an array of tokens of which some tokens may describe a redirect target
|
||||
* @return the redirect target described by the last token that describes a redirect target, or the default redirect
|
||||
* target if no token describes a redirect target
|
||||
*/
|
||||
private getRedirectTarget(tokens: string[]): ["default"] | ["write" | "append", string] {
|
||||
let redirectTarget: ["default"] | ["write" | "append", string] = ["default"];
|
||||
|
@ -554,7 +531,6 @@ export class InputParser {
|
|||
* Parses options and arguments.
|
||||
*
|
||||
* @param tokens the tokens that form the options and arguments
|
||||
* @return the options and arguments as `[options, arguments]`
|
||||
*/
|
||||
private parseOpts(tokens: string[]): [{ [key: string]: string | null }, string[]] {
|
||||
const options: { [key: string]: string | null } = {};
|
||||
|
|
|
@ -84,8 +84,6 @@ export class Terminal {
|
|||
|
||||
/**
|
||||
* Returns the input the user has entered in the HTML element.
|
||||
*
|
||||
* @return the input the user has entered in the HTML element
|
||||
*/
|
||||
private get inputText(): string {
|
||||
return this.input.innerHTML.replaceAll(/<br>/, "");
|
||||
|
@ -102,8 +100,6 @@ export class Terminal {
|
|||
|
||||
/**
|
||||
* Returns the terminal output that is being displayed.
|
||||
*
|
||||
* @return the terminal output that is being displayed
|
||||
*/
|
||||
private get outputText(): string {
|
||||
return this.output.innerHTML;
|
||||
|
@ -120,8 +116,6 @@ export class Terminal {
|
|||
|
||||
/**
|
||||
* Returns the current prefix text.
|
||||
*
|
||||
* @return the current prefix text
|
||||
*/
|
||||
private get prefixText(): string {
|
||||
return this.prefixDiv.innerHTML;
|
||||
|
@ -138,8 +132,6 @@ export class Terminal {
|
|||
|
||||
/**
|
||||
* Returns how many lines the user has scrolled up in the terminal.
|
||||
*
|
||||
* @return how many lines the user has scrolled up in the terminal
|
||||
*/
|
||||
private get scroll(): number {
|
||||
return -Math.round(parseCssPixels(this.terminal.style.marginBottom) / this.lineHeight);
|
||||
|
@ -170,8 +162,6 @@ export class Terminal {
|
|||
|
||||
/**
|
||||
* Returns `true` if and only if the input field does not display the user's input.
|
||||
*
|
||||
* @return `true` if and only if the input field does not display the user's input
|
||||
*/
|
||||
private get isInputHidden(): boolean {
|
||||
return this.input.classList.contains("terminalCurrentFocusInputHidden");
|
||||
|
@ -374,7 +364,6 @@ export class InputHistory {
|
|||
* Returns the entry at the given index, or an empty string if the index is negative.
|
||||
*
|
||||
* @param index the index to return the entry of, where `0` is the newest entry and `-1` returns an empty string
|
||||
* @return the entry at the given index, or an empty string if the index is `-1`
|
||||
* @throws if the index is out of bounds and not `-1`
|
||||
*/
|
||||
getEntry(index: number): string {
|
||||
|
@ -389,9 +378,6 @@ export class InputHistory {
|
|||
* entry.
|
||||
*
|
||||
* The read counter is decremented if possible.
|
||||
*
|
||||
* @return the next (newer) entry in the history, or an empty string if the read index has gone past the newest
|
||||
* entry
|
||||
*/
|
||||
nextEntry(): string {
|
||||
this.index--;
|
||||
|
@ -406,9 +392,6 @@ export class InputHistory {
|
|||
* entry.
|
||||
*
|
||||
* The read counter is incremented if possible.
|
||||
*
|
||||
* @return the previous (older) entry in the history, or the oldest entry if the read index is already at the oldest
|
||||
* entry
|
||||
*/
|
||||
previousEntry(): string {
|
||||
this.index++;
|
||||
|
|
|
@ -26,8 +26,6 @@ export class UserList {
|
|||
|
||||
/**
|
||||
* Returns a copy of the list of all users.
|
||||
*
|
||||
* @return a copy of the list of all users
|
||||
*/
|
||||
get users(): User[] {
|
||||
return this._users.slice();
|
||||
|
@ -38,7 +36,6 @@ export class UserList {
|
|||
* Returns `true` if and only if a user with the given name exists.
|
||||
*
|
||||
* @param name the name of the user to check
|
||||
* @return `true` if and only if a user with the given name exists
|
||||
*/
|
||||
has(name: string): boolean {
|
||||
return this.get(name) !== undefined;
|
||||
|
@ -48,7 +45,6 @@ export class UserList {
|
|||
* Returns the user with the given name, or `undefined` if there is no such user.
|
||||
*
|
||||
* @param name the name of the user to return
|
||||
* @return the user with the given name, or `undefined` if there is no such user
|
||||
*/
|
||||
get(name: string): User | undefined {
|
||||
return this._users.find(it => it.name === name);
|
||||
|
|
Loading…
Reference in New Issue