DEV Community

Cover image for Turn Your Resume Into an Interactive CLI in 10 minutes using TypeScript
Christian
Christian

Posted on • Edited on

Turn Your Resume Into an Interactive CLI in 10 minutes using TypeScript

There are tons of creative portfolio sites out there, but it takes a lot of effort to build a website that stands out. Instead of building the perfect portfolio site, what if you built an interactive resume CLI? That also sounds difficult, but I'm going to show you how to do it in under 10 minutes using a CLI generator I created.

We need TypeScript because this library generates the CLI by parsing the parameter types of our CLI functions. TypeScript provides enough context for the library to generate complex terminal interactions with minimal effort from you as the developer.

Note: This library is an alpha release, so some bugs are expected. There are also currently some limitations so for now keep all your cli code in index.ts.


Setup

We first start by initializing a new CLI project using npx.

npx @christianjuth/ts-cli-generator
Enter fullscreen mode Exit fullscreen mode

Enter whatever you like when prompted for the cli-name, but I recommend some combination of your name and resume.

$ npx @christianjuth/ts-cli-generator
✔ Enter a name for your cli … christianjuth-resume
✔ Creating project files
⠧ Installing npm dependencies
Enter fullscreen mode Exit fullscreen mode

Select math-cli as the starting template.

✔ Enter a name for your cli … christianjuth-resume
? Pick a template › - Use arrow-keys. Return to submit.
❯   math-cli
    rss-reader-cli
    stocks-cli
    with-auth
Enter fullscreen mode Exit fullscreen mode

This gives us the following files:

christianjuth-resume
├── index.ts
├── package.json
├── README.md
└── tsconfig.json
Enter fullscreen mode Exit fullscreen mode

If we open index.ts we should see something like this:

import { call, CLI } from "@christianjuth/ts-cli-generator";

/**
 * Add two numbers
 */
function add(x: number, y: number) {
  console.log(x + y);
}

/**
 * Subtract two numbers
 */
function _subtract(x: number, y: number) {
  return x - y;
}

/**
 * Add then subtract as separate interactioins
 */
async function addSubtract(x: number, y: number) {
  console.log(x + y);
  // call allows you to call a cli function
  // from within another cli function
  console.log(await call(_subtract)());
}

/**
 * Get the length of a string
 */
function lengthOfString(str: string) {
  console.log(str.length);
}

export const cli: CLI = {
  add,
  addSubtract,
  lengthOfString,
  // underscore means function is available but hidden
  _subtract,
};
Enter fullscreen mode Exit fullscreen mode

The above index.ts generates these commands when we run npm start:

christianjuth-resume CLI 0.0.0

Powered by @christianjuth/ts-cli-generator

Commands:
  add               Add two numbers
  add-subtract      Add then subtract as separate interactions
  length-of-string  Get the length of a string

Options:
  -i, --interactive Run CLI in interactive mode
Enter fullscreen mode Exit fullscreen mode

We have also get the following npm scripts:

npm start <cli-command> # more on this later
npm start # excluding <cli command> gives us usage
npm run dev <cli-command> # same as start but with nodemon
npm run build # build the cli
Enter fullscreen mode Exit fullscreen mode

Customize your resume

We will use the npm openurl package so we can have our CLI programmatically open links in the browser. Start by installing openurl and it's types.

npm i openurl
npm i -D @types/openurl
Enter fullscreen mode Exit fullscreen mode

Start by adding some social links to your resume. Replace the contents of index.ts with the following:

import { CLI } from "@christianjuth/ts-cli-generator";
import { open, mailto } from "openurl";

/**
 * Follow me on Twitter 🐦
 */
function twitter() {
  open("<your Twitter url>");
}

/**
 * Connect with my on LinkedIn 👔
 */
function linkedin() {
  open("<your LinkedIn url>");
}

/**
 * See my projects on GitHub 🚀
 */
function github() {
  open("<your GitHub url>");
}

export const cli: CLI = {
  twitter,
  linkedin,
  github,
};
Enter fullscreen mode Exit fullscreen mode

If we run our CLI using npm start we get the following commands:

$ npm start

> christianjuth-resume@0.0.0 start
> ts-cli-generator build && node .

✔ Detecting cli functions
✔ Writing cli files
✔ Emitting CLI build
christianjuth-resume CLI 0.0.0

Powered by @christianjuth/ts-cli-generator

Commands:
  twitter   Follow me on Twitter 🐦
  linkedin  Connect with my on LinkedIn 👔
  github    See my projects on GitHub 🚀
Enter fullscreen mode Exit fullscreen mode

We can open the links by running:

# npm start <cli-command>
npm start twitter
npm start linkedin
npm start github
Enter fullscreen mode Exit fullscreen mode

Add some projects to our resume

Add the following to index.ts

// prev functions...

/**
 * Check out some of my projects ✨
 */
 function projects(str: "project1" | "project2") {
  switch (str) {
    case "project1":
      open("https://...");
      break;
    case "project2":
      open("https://...");
  }
}

export const cli: CLI = {
  twitter,
  linkedin,
  github,
  projects
};
Enter fullscreen mode Exit fullscreen mode

If we run npm start projects, we now get a CLI interface to select what project we want to open.

$ npm start projects

> christianjuth-resume@0.0.0 start
> ts-cli-generator build && node . "projects"

✔ Detecting cli functions
✔ Writing cli files
✔ Emitting CLI build
? Select praram type for str › - Use arrow-keys. Return to submit.
❯   project1
    project2
Enter fullscreen mode Exit fullscreen mode

Select a project and press enter to view the project in the browser.


Add a contact form

For simplicity, we will create a contact form that opens a mailto link, but you could easily make a POST request instead.

And add the following to index.ts:

// prev functions...

/**
 * Contact me 📪
 */
function contact(info: {
  subject: string;
  name: string;
  email: string;
  phoneNumber: string;
}) {
  const { subject, name, email, phoneNumber } = info;
  const EMAIL = "your.email@example.com";

  const message = `
    Name: ${name}
    Email: ${email}
    ${phoneNumber ? `Number: ${phoneNumber}` : ""}
  `;

  mailto([EMAIL], {
    subject,
    body: message,
  });
}
Enter fullscreen mode Exit fullscreen mode

Notice how our CLI is able to handle objects as parameters (it can even handle nested objects). Arrays aren't supported yet, but coming soon.

Try running yarn start contact and see what happens.

The final product

The final version of index.ts is posted at the bottom if you want to see it for reference.

Install the CLI locally by running:

npm run build
npm link

# substitute christianjuth-resume with your cli name
christianjuth-resume # print usage
christianjuth-resume <cli-command> # run command
Enter fullscreen mode Exit fullscreen mode

Next steps

You could publish your package to NPM to easily share with others, but for this tutorial we are going to use GitHub because it's simpler.

Before you can share your package with others, you must:

  • Create a GitHub repo
  • Build your project via npm run build before committing
  • Commit and push your CLI project to GitHub
  • We can now run the CLI directly off of GitHub using npm exec

You can check out my repo here.

Normally I would use npx, but I've had better luck with npm exec when working with GitHub repos.

# substitute github:christianjuth/resume-cli with your GitHub repo username/repo
npm exec github:christianjuth/resume-cli
npm exec github:christianjuth/resume-cli <cli command>
Enter fullscreen mode Exit fullscreen mode

Thanks for reading!

Out final CLI has these commands:

christianjuth-resume CLI 0.0.0

Powered by @christianjuth/ts-cli-generator

Commands:
  twitter   Follow me on Twitter 🐦
  linkedin  Connect with my on LinkedIn 👔
  github    See my projects on GitHub 🚀
  projects  Check out some of my projects ✨
  contact   Contact me 📪
Enter fullscreen mode Exit fullscreen mode

And our final index.ts file looks like this:

import { call, CLI } from "@christianjuth/ts-cli-generator";
import { open, mailto } from "openurl";

/**
 * Follow me on Twitter 🐦
 */
function twitter() {
  open("<your Twitter url>");
}

/**
 * Connect with my on LinkedIn 👔
 */
function linkedin() {
  open("<your LinkedIn url>");
}

/**
 * See my projects on GitHub 🚀
 */
function github() {
  open("<your GitHub url>");
}

/**
 * Check out some of my projects ✨
 */
function projects(str: "project1" | "project2") {
  switch (str) {
    case "project1":
      open("https://...");
      break;
    case "project2":
      open("https://...");
  }
}

/**
 * Contact me 📪
 */
function contact(info: {
  subject: string;
  name: string;
  email: string;
  phoneNumber: string;
}) {
  const { subject, name, email, phoneNumber } = info;
  const EMAIL = "your.email@example.com";

  const message = `
    Name: ${name}
    Email: ${email}
    ${phoneNumber ? `Number: ${phoneNumber}` : ""}
  `;

  mailto([EMAIL], {
    subject,
    body: message,
  });
}

export const cli: CLI = {
  twitter,
  linkedin,
  github,
  projects,
  contact,
};
Enter fullscreen mode Exit fullscreen mode

Top comments (0)