Boost your productivity by creating your own CLI command with typescript and OCLIF (Part 2) ๐
Raphael MANSUY
Posted on January 20, 2021
Context
OCLIF is a wonderful framework that makes it easy to develop a professional CLI command. Let's see how we can create a CLI command that will delight your end-user in less than 3 minutes.
The final project is published on https://github.com/raphaelmansuy/matcha-stock
Add a ๐ on the project if you have enjoyed this tutorial โค๏ธ
$ matcha-stock -symbol=MSFT
Lets go ! ๐
Create a new command with OCLIF (30 seconds โฐ)
npx oclif single matcha-stock
cd matcha-stock
./bin.run
Result:
OCLIF generates a starting project for my command.
โฏ npx oclif single matcha-stock
_-----_ โญโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
| | โ Time to build a โ
|--(o)--| โ single-command CLI with โ
`---------ยด โ oclif! Version: 1.16.1 โ
( _ยดU`_ ) โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
/___A___\ /
| ~ |
__'.___.'__
ยด ` |ยฐ ยด Y `
npm package name matcha-stock
? command bin name the CLI will export matcha-stock
? description A command to get stocks information
? author Raphael MANSUY @raphaelmansuy
? version 0.0.1
? license MIT
? Who is the GitHub owner of repository (https://github.com/OWNER/repo) raphaelmansuy
? What is the GitHub name of repository (https://github.com/owner/REPO) matcha-stock
? Select a package manager yarn
? TypeScript Yes
? Use eslint (linter for JavaScript and Typescript) Yes
? Use mocha (testing framework) Yes
Code created by OCLIF
โโโ README.md
โโโ bin
โ โโโ run
โ โโโ run.cmd
โโโ package.json
โโโ src
โ โโโ index.ts
โโโ test
โ โโโ index.test.ts
โ โโโ mocha.opts
โ โโโ tsconfig.json
โโโ tsconfig.json
โโโ yarn.lock
Content of src/index.ts
import { Command, flags } from "@oclif/command"
class MatchaStock extends Command {
static description = "describe the command here"
static flags = {
// add --version flag to show CLI version
version: flags.version({ char: "v" }),
help: flags.help({ char: "h" }),
// flag with a value (-n, --name=VALUE)
name: flags.string({ char: "n", description: "name to print" }),
// flag with no value (-f, --force)
force: flags.boolean({ char: "f" })
}
static args = [{ name: "file" }]
async run() {
const { args, flags } = this.parse(MatchaStock)
const name = flags.name ?? "world"
this.log(`hello ${name} from ./src/index.ts`)
if (args.file && flags.force) {
this.log(`you input --force and --file: ${args.file}`)
}
}
}
export = MatchaStock
โ OCLIF has created a template class that represents the skeleton of my command.
Starting from the generated code I can:
- ๐ช add flags such as
--symbol
- ๐ modify the implementation of the
run()
method
Add the support of the flag --symbol
(40 seconds โฐ)
import { Command, flags } from "@oclif/command"
class MatchaStock extends Command {
static description =
"A simple command to retrieve stock information from Yahoo Finance"
static flags = {
// add --version flag to show CLI version
version: flags.version({ char: "v" }),
help: flags.help({ char: "h" }),
// Add Support of of -symbol flag
// flag with a value (-s, --symbol=VALUE)
symbol: flags.string({
char: "s", // Alias for my flag
description: "stock symbol to retrieve", // A description of the symbol flag
required: true, // The flag symbol is required ๐ The command will abort of the flag is not provide
helpValue: "MSFT" // An example of flag value (MSFT is the symbol for Microsoft)
})
}
async run() {
const { args, flags } = this.parse(MatchaStock)
this.log(`Get Symbol=${flags.symbol} from ./src/index.ts`)
}
}
export = MatchaStock
I can now test my command
โ
With no flag
./bin
result:
โบ Error: Missing required flag:
โบ -s, --symbol SYMBOL stock symbol to retrieve
โบ See more help with --help
โ
With flag -help
./bin -help
result:
โฏ ./bin/run -help
A simple command to retrieve stock information from Yahoo Finance
USAGE
\$ matcha-stock
OPTIONS
-h, --help show CLI help
-s, --symbol=MSFT (required) stock symbol to retrieve
-v, --version show CLI version
โ
With flag --symbol
./bin --symbol GOOG
result:
โฏ ./bin/run -symbol=GOOG
Get Symbol=ymbol=GOOG from ./src/index.ts
Add the business logic (60 seconds โฐ)
๐ Add axios as our http library.
yarn add axios
๐ Add the file ./src/getStock.ts
import axios from "axios"
export const getSingleStockInfo = async (stock: string) => {
if (!stock) {
throw new Error("Stock symbol argument required")
}
if (typeof stock !== "string") {
throw new Error(
`Invalid argument type for stock argument. Required: string. Found: ${typeof stock}`
)
}
const url = `https://query1.finance.yahoo.com/v7/finance/quote?symbols=${stock}`
const res = await axios.get(url)
const { data } = res
if (
!data ||
!data.quoteResponse ||
!data.quoteResponse.result ||
data.quoteResponse.result.length === 0
) {
throw new Error(`Error retrieving info for symbol ${stock}`)
}
const quoteResponse = data.quoteResponse.result[0]
return quoteResponse
}
๐ Modify the src/index.ts
file such as:
import { Command, flags } from "@oclif/command"
import { getSingleStockInfo } from "./getStocks"
class MatchaStock extends Command {
static description = `A simple command to retrieve stock information from Yahoo Finance.\nA simple command to retrieve stock information from Yahoo Finance.\n\n Created with โค๏ธ by Elitizon (https://www.elitizon.com)`
static flags = {
// add --version flag to show CLI version
version: flags.version({ char: "v" }),
help: flags.help({ char: "h" }),
// Add Support of of -symbol flag
// flag with a value (-s, --symbol=VALUE)
symbol: flags.string({
char: "s", // Alias for my flag
description: "stock symbol to retrieve", // A description of the symbol flag
required: true, // The flag symbol is required ๐ The command will abort of the flag is not provide
helpValue: "MSFT" // An example of flag value (MSFT is the symbol for Microsoft)
})
}
async run() {
const { flags } = this.parse(MatchaStock)
const res = await getSingleStockInfo(flags.symbol)
// Print the result as tabular
console.table(res)
}
}
export = MatchaStock
๐ Test the command
โฏ ./bin/run -s=MSFT
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ (index) โ Values โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ language โ 'en-US' โ
โ region โ 'US' โ
โ quoteType โ 'EQUITY' โ
โ quoteSourceName โ 'Delayed Quote' โ
โ triggerable โ true โ
โ currency โ 'USD' โ
โ firstTradeDateMilliseconds โ 511108200000 โ
โ priceHint โ 2 โ
โ marketState โ 'POSTPOST' โ
โ postMarketChangePercent โ 0.31417143 โ
Publish the command to NPM.org (30 seconds โฐ)
npm publish
โ The package is now published on npm.org at https://www.npmjs.com/package/matcha-stock
- ๐ You have to change the name of the package if the package is already registered on NPM.
- ๐ The package version must be updated each time you publish
Test your command (10 seconds โฐ)
npm install -g matcha-stock
matcha-stock -s=MSFT
Conclusion
OCLIF is an impressive framework. With OCLIF it's easy to create:
- Single-Command CLI
- Multi-command CLI
Main features:
- ๐บ Flag/Argument parsing
- ๐ Super Speed
- ๐ Include a CLI generator to speed the development of commands
- Testing Helpers
- Auto-Documentation
- Plugins
- Hooks
OCLIF is available on Github and maintained by Matt Graham, Paul Elliott and Chris Castle and funded by Heroku ๐
Posted on January 20, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.