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 ❤️
1$ matcha-stock -symbol=MSFT
1npx oclif single matcha-stock2cd matcha-stock3./bin.run
Result:
OCLIF generates a starting project for my command.
1❯ npx oclif single matcha-stock23 _-----_ ╭──────────────────────────╮4 | | │ Time to build a │5 |--(o)--| │ single-command CLI with │6 `---------´ │ oclif! Version: 1.16.1 │7 ( _´U`_ ) ╰──────────────────────────╯8 /___A___\ /9 | ~ |10 __'.___.'__11 ´ ` |° ´ Y `1213 npm package name matcha-stock14? command bin name the CLI will export matcha-stock15? description A command to get stocks information16? author Raphael MANSUY @raphaelmansuy17? version 0.0.118? license MIT19? Who is the GitHub owner of repository (https://github.com/OWNER/repo) raphaelmansuy20? What is the GitHub name of repository (https://github.com/owner/REPO) matcha-stock21? Select a package manager yarn22? TypeScript Yes23? Use eslint (linter for JavaScript and Typescript) Yes24? Use mocha (testing framework) Yes
Code created by OCLIF
1├── README.md2├── bin3│ ├── run4│ └── run.cmd5├── package.json6├── src7│ └── index.ts8├── test9│ ├── index.test.ts10│ ├── mocha.opts11│ └── tsconfig.json12├── tsconfig.json13└── yarn.lock
Content of src/index.ts
1import { Command, flags } from "@oclif/command"23class MatchaStock extends Command {4 static description = "describe the command here"56 static flags = {7 // add --version flag to show CLI version8 version: flags.version({ char: "v" }),9 help: flags.help({ char: "h" }),10 // flag with a value (-n, --name=VALUE)11 name: flags.string({ char: "n", description: "name to print" }),12 // flag with no value (-f, --force)13 force: flags.boolean({ char: "f" })14 }1516 static args = [{ name: "file" }]1718 async run() {19 const { args, flags } = this.parse(MatchaStock)2021 const name = flags.name ?? "world"22 this.log(`hello ${name} from ./src/index.ts`)23 if (args.file && flags.force) {24 this.log(`you input --force and --file: ${args.file}`)25 }26 }27}2829export = MatchaStock
✅ OCLIF has created a template class that represents the skeleton of my command.
Starting from the generated code I can:
--symbol
run()
method--symbol
(40 seconds ⏰)1import { Command, flags } from "@oclif/command"23class MatchaStock extends Command {4 static description =5 "A simple command to retrieve stock information from Yahoo Finance"67 static flags = {8 // add --version flag to show CLI version9 version: flags.version({ char: "v" }),10 help: flags.help({ char: "h" }),11 // Add Support of of -symbol flag12 // flag with a value (-s, --symbol=VALUE)13 symbol: flags.string({14 char: "s", // Alias for my flag15 description: "stock symbol to retrieve", // A description of the symbol flag16 required: true, // The flag symbol is required 👉 The command will abort of the flag is not provide17 helpValue: "MSFT" // An example of flag value (MSFT is the symbol for Microsoft)18 })19 }2021 async run() {22 const { args, flags } = this.parse(MatchaStock)2324 this.log(`Get Symbol=${flags.symbol} from ./src/index.ts`)25 }26}2728export = MatchaStock
I can now test my command
✅ With no flag
1./bin
result:
1› Error: Missing required flag:2 › -s, --symbol SYMBOL stock symbol to retrieve3 › See more help with --help
✅ With flag -help
1./bin -help
result:
1❯ ./bin/run -help2A simple command to retrieve stock information from Yahoo Finance34USAGE5\$ matcha-stock67OPTIONS8-h, --help show CLI help9-s, --symbol=MSFT (required) stock symbol to retrieve10-v, --version show CLI version
✅ With flag --symbol
1./bin --symbol GOOG
result:
1❯ ./bin/run -symbol=GOOG2Get Symbol=ymbol=GOOG from ./src/index.ts
👉 Add axios as our http library.
1yarn add axios
👉 Add the file ./src/getStock.ts
1import axios from "axios"23export const getSingleStockInfo = async (stock: string) => {4 if (!stock) {5 throw new Error("Stock symbol argument required")6 }78 if (typeof stock !== "string") {9 throw new Error(10 `Invalid argument type for stock argument. Required: string. Found: ${typeof stock}`11 )12 }1314 const url = `https://query1.finance.yahoo.com/v7/finance/quote?symbols=${stock}`1516 const res = await axios.get(url)1718 const { data } = res19 if (20 !data ||21 !data.quoteResponse ||22 !data.quoteResponse.result ||23 data.quoteResponse.result.length === 024 ) {25 throw new Error(`Error retrieving info for symbol ${stock}`)26 }2728 const quoteResponse = data.quoteResponse.result[0]2930 return quoteResponse31}
👉 Modify the src/index.ts
file such as:
1import { Command, flags } from "@oclif/command"2import { getSingleStockInfo } from "./getStocks"3class MatchaStock extends Command {4 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)`56 static flags = {7 // add --version flag to show CLI version8 version: flags.version({ char: "v" }),9 help: flags.help({ char: "h" }),10 // Add Support of of -symbol flag11 // flag with a value (-s, --symbol=VALUE)12 symbol: flags.string({13 char: "s", // Alias for my flag14 description: "stock symbol to retrieve", // A description of the symbol flag15 required: true, // The flag symbol is required 👉 The command will abort of the flag is not provide16 helpValue: "MSFT" // An example of flag value (MSFT is the symbol for Microsoft)17 })18 }1920 async run() {21 const { flags } = this.parse(MatchaStock)22 const res = await getSingleStockInfo(flags.symbol)23 // Print the result as tabular24 console.table(res)25 }26}2728export = MatchaStock
👉 Test the command
1❯ ./bin/run -s=MSFT2┌───────────────────────────────────┬─────────────────────────┐3│ (index) │ Values │4├───────────────────────────────────┼─────────────────────────┤5│ language │ 'en-US' │6│ region │ 'US' │7│ quoteType │ 'EQUITY' │8│ quoteSourceName │ 'Delayed Quote' │9│ triggerable │ true │10│ currency │ 'USD' │11│ firstTradeDateMilliseconds │ 511108200000 │12│ priceHint │ 2 │13│ marketState │ 'POSTPOST' │14│ postMarketChangePercent │ 0.31417143 │
1npm publish
✅ The package is now published on npm.org at https://www.npmjs.com/package/matcha-stock
1npm install -g matcha-stock2matcha-stock -s=MSFT
OCLIF is an impressive framework. With OCLIF it's easy to create:
Main features:
OCLIF is available on Github and maintained by Matt Graham, Paul Elliott and Chris Castle and funded by Heroku 🎉
We deliver high quality blog posts written by professionals monthly. And we promise no spam.