UNPKG

@zqui/react-terminal

Version:

A react component that renders a bash-like terminal.

416 lines (407 loc) 8.4 kB
import React, { SetStateAction } from "react"; import IExchange, { ObjExchange } from "../types/Exchange"; import IUserCommands from "../types/Commands"; import { argsNotReqd, argsReqd, commandNotFound, invalidTheme, tooManyArgs, } from "../errors/Errors"; import { cat, cd, getPwd, ls, mkdir, rm } from "./InBuiltCommandsProcessors"; import { appendError, appendOutput } from "../utils/helpers"; import ITheme from "../types/Theme"; import { themes } from "../themes"; type CommandOutput = string | React.JSX.Element; type SyncCommandExecutor = () => CommandOutput; type AsyncCommandExecutor = () => Promise<CommandOutput>; type CommandExecutorWithArgs = (args: string) => CommandOutput; type CommandExecutor = | CommandOutput | SyncCommandExecutor | AsyncCommandExecutor | CommandExecutorWithArgs; // ============================= // HANDLES USER DEFINED COMMANDS // ============================= const executeAsyncCommand = async ( executor: AsyncCommandExecutor, setExchangeHistory: React.Dispatch<SetStateAction<IExchange[]>>, fullCommand: string, pwd: string, prompt: string, cliLoader: React.JSX.Element ) => { setExchangeHistory((prev) => [ ...prev, { command: fullCommand, output: cliLoader, prompt: prompt, pwd: pwd }, ]); try { const resolvedVal = await executor(); setExchangeHistory((prev) => { const last = prev.pop(); (last as ObjExchange).output = resolvedVal; return [...prev, last!]; }); } catch (error) { // TODO: Create an error component for this const errorMessage = "An error occurred while executing the command."; setExchangeHistory((prev) => { const last = prev.pop(); (last as ObjExchange).output = errorMessage; return [...prev, last!]; }); } }; const executeSyncCommand = ( executor: SyncCommandExecutor, setExchangeHistory: React.Dispatch<SetStateAction<IExchange[]>>, fullCommand: string, pwd: string, prompt: string ) => { appendOutput(setExchangeHistory, executor(), fullCommand, pwd, prompt); }; const executeCommand = async ( executor: CommandExecutor, setExchangeHistory: React.Dispatch<SetStateAction<IExchange[]>>, fullCommand: string, pwd: string, prompt: string, cliLoader: React.JSX.Element ) => { if (typeof executor === "function") { if (executor.constructor.name === "AsyncFunction") { await executeAsyncCommand( executor as AsyncCommandExecutor, setExchangeHistory, fullCommand, pwd, prompt, cliLoader ); } else { executeSyncCommand( executor as SyncCommandExecutor, setExchangeHistory, fullCommand, pwd, prompt ); } } else { appendOutput(setExchangeHistory, executor, fullCommand, pwd, prompt); } }; export const processUserCommand = async ( base: string, argsArr: string[], commands: IUserCommands, setExchangeHistory: React.Dispatch<SetStateAction<IExchange[]>>, pwd: string, prompt: string, cliLoader: React.JSX.Element ) => { const args = argsArr.join(" "); const fullCommand = `${base} ${args}`; if (commands[`${fullCommand}`]) { await executeCommand( commands[`${fullCommand}`] as CommandExecutor, setExchangeHistory, fullCommand, pwd, prompt, cliLoader ); } else if (commands[base]) { const executor = commands[base]; if (typeof executor === "function") { await executeCommand( () => (executor as CommandExecutorWithArgs)(args), setExchangeHistory, fullCommand, pwd, prompt, cliLoader ); } else { await executeCommand( executor as CommandExecutor, setExchangeHistory, fullCommand, pwd, prompt, cliLoader ); } } else { appendOutput( setExchangeHistory, commandNotFound(base), fullCommand, pwd, prompt ); } }; // ========================= // HANDLES BUILT IN COMMANDS // ========================= export const processInBuiltCommand = ( base: string, pwd: string, argsArr: string[], setExchangeHistory: React.Dispatch<SetStateAction<IExchange[]>>, prompt: string, setPwd: React.Dispatch<React.SetStateAction<string>>, structure: any, setStructure: React.Dispatch<React.SetStateAction<any>>, setTerminalTheme: React.Dispatch<React.SetStateAction<ITheme>> ) => { const args = argsArr.join(" "); const fullCommand = `${base} ${args}`; switch (base) { // Handle clear // case "clear": { if (args.length !== 0) { appendError( setExchangeHistory, argsNotReqd(base), fullCommand, pwd, prompt ); } else setExchangeHistory([]); // Clears the terminal exchange history } break; // Handle echo // case "echo": { // TODO: Handle case for strings passed with "" & ''. appendOutput( setExchangeHistory, args, fullCommand, pwd, prompt ); } break; // Handle cd // case "cd": { if (argsArr.length > 1) { appendError( setExchangeHistory, tooManyArgs(base), fullCommand, pwd, prompt ); } else if (argsArr.length < 1) { appendOutput( setExchangeHistory, args, fullCommand, pwd, prompt ); } else { cd( pwd, prompt, setPwd, argsArr, structure, setExchangeHistory, fullCommand ); } } break; // Handle ls // case "ls": { if (argsArr.length > 1) { appendError( setExchangeHistory, tooManyArgs(base), fullCommand, pwd, prompt ); } else { ls( setExchangeHistory, argsArr, structure, pwd, prompt, fullCommand ); } } break; // Handle cat // case "cat": { if (argsArr.length > 1) { appendError( setExchangeHistory, tooManyArgs(base), fullCommand, pwd, prompt ); } else if (argsArr.length < 1) { appendError( setExchangeHistory, argsReqd(base, "YOUR-FILE-NAME"), fullCommand, pwd, prompt ); } else { cat( setExchangeHistory, pwd, prompt, fullCommand, argsArr, structure ); } } break; // Handle pwd // case "pwd": { if (argsArr.length !== 0) { appendError( setExchangeHistory, argsNotReqd(base), fullCommand, pwd, prompt ); } else getPwd(pwd, prompt, setExchangeHistory); } break; // Handle mkdir // case "mkdir": { if (argsArr.length > 1) { appendError( setExchangeHistory, tooManyArgs(base), fullCommand, pwd, prompt ); } else if (argsArr.length < 1) { appendError( setExchangeHistory, argsReqd(base, "NEW-DIR-NAME"), fullCommand, pwd, prompt ); } else { mkdir( setExchangeHistory, pwd, prompt, argsArr, structure, fullCommand, setStructure ); } } break; // Handle rm // case "rm": { if (argsArr.length > 1) { appendError( setExchangeHistory, tooManyArgs(base), fullCommand, pwd, prompt ); } else if (argsArr.length < 1) { appendError( setExchangeHistory, argsReqd(base, "YOUR-FILE/DIR"), fullCommand, pwd, prompt ); } else { rm( setExchangeHistory, argsArr, pwd, prompt, structure, setStructure, fullCommand ); } } break; // Handle date // case "date": { if (argsArr.length !== 0) { appendError( setExchangeHistory, tooManyArgs(base), fullCommand, pwd, prompt ); } else { const date = new Date(); appendOutput( setExchangeHistory, date.toString(), fullCommand, pwd, prompt ); } } break; // Handle setTheme // case "setTheme": { if (argsArr.length > 1) { appendError( setExchangeHistory, tooManyArgs(base), fullCommand, pwd, prompt ); } else if (!argsArr[0]) { appendError( setExchangeHistory, argsReqd(base, "dark"), fullCommand, pwd, prompt ); } else if (!Object.keys(themes).includes(argsArr[0])) { appendError( setExchangeHistory, invalidTheme(argsArr[0]), fullCommand, pwd, prompt ); } else setTerminalTheme(themes[argsArr[0]] as ITheme); } } };