Javascript is a highly versatile language. With the addition of Node Js, it can be executed not only on servers specifically, but also on personal computers. Thus, javascript (and typescript) can be leveraged for writing scripts and applications for the console. This can be very useful for people who are fluent in Javascript but not in bash or other scripting languages; it is also arguably more practical to use a higher level language for creating larger cli applications, depending upon the circumstances of the situation. In the sections below, we provide an example app powered by our library, then we outline the process of creating a CLI with @byte-this/js-cli.
Cli-Js App Example
The app below resembles a console line application and has a few example commands in a cli-like interface:
Enter the next command to execute
Using Javascript and Typescript on the Command Line
With Node Js installed, javascript can be used directly in a command line terminal. Typing node will take you into a Javascript shell where js statements can be directly executed. Typing node :scriptpath.js: will execute a Javascript script at :scriptpath.js:
. ts-node can be installed via npm to execute typescript files similarly. This means we can create different types of scripts:
- Scripts which are too complex to write with lower level scripting languages.
- Quick, one-time scripts for taking care of certain one-time actions.
- Reusable scripts to facilitate repetitive tasks and automation.
- Command line applications: CLIs, which provide an interactive interface to help the user complete some actions.
The last option: Cli, can also be leveraged to accomplish the other tasks listed above. We have created an API which takes of the lower level tasks of creating and running a Cli (which we use ourselves to help automate or facilitate certain DevOps processes).
Using @byte-this/js-cli
The project is available as a consumable package and the code is available on Git:
- Npm Package to directly install and use.
- Github Project to view the source code.
To get started now: you can directly install via npm:
There are a few things we need to get together:
- Collection of Commands: the cli app will run based on a list of commands which includes its name, description, required params, and code to execute.
- Input and Output: the app will get user input and output contents based on the services provided. The library comes with default console line input and output services.
- Program Configurations: the program will behave differently based on input configurations.
The sections below will outline each requirement.
Cli Commands
One of the central concepts of the app is a command, which is an encapsulation of some action to execute and its required parameters. The following are type definitions for a commmand, and a command input parameter, which is necessary for commands which require user input.
A few example commands from the example application are shown below. Each exemplifies a different type of command with different user param requirements.
Cli Command Collection
The cli command collection is an encapsulation of one or more collections which will be used by the cli app driver to run the app. In most use cases, such as the example above, a collection based on an array is suitable, as shown in the code box below. In more advanced use cases, a custom collection can be used which contains some logic to alter the commands after each execution based on some logic. If this approach is taken, the list of commands may change after each command execution.
Outputter and Input Requestor
The cli-app requires a cliOutputter and cliUserInputRequestor to be injected. These are responsible for outputting strings and objects to the screen and getting input from the user. The library comes with default services for these:
- ConsoleOutputter: outputs data to the console window and provides separate colors for debug, message, warning, and error.
- ConsoleUserInputRequestor: prompt the user to enter or make a selection in the console window.
If desired, you can write your own outputter and/or user input requestor to encapsulate different functionality for input and output. Note: when we created our cli-app example for this article, the only thing we needed to do was provide different output and input services; we were able to directly re-use everything else.
App Options
The app runner will run with some default options if none are provided. In most cases, the defaults will be fine, but if you'd like to change some default behavior, you can do so by injecting different options. The interface below specifices all options; you may create an object which contains only the options you need to set, and the app will fill in the rest.
Putting it All Together
Once we have everything above defined, we can inject it all into the CliApplication object:
A Note on Alternative Strategies
The reason we are able to showcase an example app on this website (which is not a console) is because we are able to do the following:
- Create Alternate I/O Services: we created alternate services which implement the interfaces for the outputter and user input requestor. (If you are working in javascript, there are no interfaces but you can still satisfy the types).
- Inject the Alternate Services into the App: since the app was built based on dependency inversion, we can inject our alternate services into the app without any changes to the app itself.
Since the i/o services are injectable, it is possible to use this library in many different cases, such as:
- Console app
- Website app
- Desktop app, using something like Electron
- Mobile app
The UI itself can look like a command line interface, such as the example app, or the outputter can implement the 'output commands' method differently to show the commands as buttons or some other interface.