npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fn-to-cli

v2.0.3

Published

Convert typescript functions to CLI executables.

Downloads

53

Readme

fn-to-cli

Table of contents

Installation

npm install fn-to-cli

Description

This module converts typescript functions to CLI.

Code coverage

Code coverage is around 90%.

Quick start

For a quick start:

  1. execute from terminal:

    npx fn-to-cli --help;
  2. add @CLI JSDoc tag comment to the functions you want to convert to CLI

  3. compile your typescript project to javascript project

  4. execute from terminal:

    npx fn-to-cli;

If something goes wrong you will receive helpful error messages that will guide you on resolving the error.

Example

  1. Create a new folder and set it as your current working directory:

    mkdir example; cd ./example;
  2. Create ./package.json with the following content:

    {
        "name": "some-random-package-name",
        "version": "1.0.0",
        "private": true,
        "main": "./dist/index.js",
        "bin": "bin/bin.js",
        "scripts": {
            "build-ts": "rm -rf ./dist; npx tsc",
            "build-bin": "rm -rf ./bin; npx fn-to-cli",
            "build": "npm run build-ts && npm run build-bin",
            "test": "jest"
        },
        "devDependencies": {
            "jest": "^26.6.3",
            "typescript": "^4.2.3"
        },
        "dependencies": {
            "fn-to-cli": "file:.."
        }
    }
        

    Notice the bin property in ./package.json. This is used by fn-to-cli as a path to output the generated CLI.

  3. Delete from ./package.json the line:

    "fn-to-cli": "../"
  4. Install fn-to-cli:

    npm install fn-to-cli;

    this will also install the rest of the dependencies.

  5. Create ./tsconfig.json with the following content:

    {
        "compilerOptions": {
            "rootDir": "./src",
            "outDir": "./dist",
            "module": "CommonJS",
            "target": "ESNext",
            "declaration": true
        },
        "exclude": [
            "node_modules"
        ]
    }
  6. Create ./src/index.ts with the following content:

    export { foo } from "./foo";
        
  7. Create ./src/foo.ts with the following content:

    /**
     * Some tag less description for command foo.
     * @CLI
     */
    export function foo(_: {
        /**
         * @description
         * Some tag full description for option `a` of command `foo`.
         */
        a: string;
        /**
         * Some tag less description for option `b` of command `foo`.
         * @default true
         * @flag V
         */
        b?: boolean;
    }): void {
        const { a } = _;
        let { b } = _;
        if (b === undefined) b = true;
        console.log(`foo executed with a = "${a}", b = ${b}`);
    }
        
  8. Create ./src/bar/bar.ts with the following content:

    /**
     * @description
     * Some tag full description for command `bar`.
     * @CLI baz
     */
    export default function bar(_: {
        /**
         * Some tag less description for option `c` of command `bar`.
         */
        c: boolean;
        /**
         * Some tag less description for option `d` of command `bar`.
         * @private
         * @default true
         */
        d?: boolean;
    }): void {
        const { c } = _;
        let { d } = _;
        if (d === undefined) d = true;
        console.log(`bar executed with c = ${c}, d = ${d}`);
    }
        
  9. Execute:

    npm run build;

    This command does two things:

    • builds typescript to javascript
    • generates the CLI
  10. Now you can use the generated CLI. Here are some examples:

    node ./bin/bin.js foo --a "'hello'";
    node ./bin/bin.js foo --a "'hello'" -V "false";
    node ./bin/bin.js baz --c "false";

Documentation

Execute the following command:

npx fn-to-cli --help

to get the CLI documentation:

CLI syntax:

  fn-to-cli fnToCLI? [[--<option> | -<flag>] <value>]#

Description:

  Converts typescript functions to CLI.

Non required options:

  -t --pathToTsconfig    : string  = "./tsconfig.json"  Path to `tsconfig.json`.
  -p --pathToPackageJson : string  = "./package.json"   Path to `package.json`.
  -s --strict            : boolean = false              For one command CLI, it is optional to write the command name when using the CLI. Give `true` to disable that.

The CLI generator works by searching deeply in the directory defined by the property compilerOptions.outDir of tsconfig.json, for all the .d.ts files that have functions with @CLI JSDoc tag. These functions become commands to the generated CLI.

The generated CLI is saved to the path defined by the bin property of package.json, and imports js functions from the directories compilerOptions.outDir, and node_modules, so it will not work if these folders are missing or moved.

Each function with the @CLI JSDoc tag has to:

  1. have a single parameter that is TypeLiteral, for example:

    {
        param1 : string,
        param2 : boolean
    }
  2. be a function declaration statement, for example:

    • incorrect:

      const foo = () => {
          //some code
      };
    • correct:

      function foo() {
          //some code
      }
  3. be named or default exported

  4. have name

  5. have description in its JSDoc comment via a @description tag or tag-less

  6. same for each property in its parameter type signature

  7. have @default JSDoc tag with initialization value for each optional parameter

  8. be inside the rootDir directory as defined by the provided tsconfig.json

  9. be in a .ts file

The functions can have:

  1. @flag JSDoc tag for any of its properties. It has to have a single letter as a value which can be used instead of the parameter names in the CLI.
  2. @cliPrivate JSDoc tag for any of its optional properties. These properties will not be visible in the documentation of the CLI and will not receive a value even if the user of the CLI provides one for them.

Motivation

A typescript function with JSDoc comments, contains all the necessary information to be converted automatically to a cli. Why would anyone waste their time doing the conversion manually? Automating that is the only maintainable solution.

Contributing

I am open to suggestions/pull request to improve this program.

You will find the following commands useful:

  • Clones the github repository of this project:

    git clone https://github.com/lillallol/fn-to-cli
  • Installs the node modules (nothing will work without them):

    npm install
  • Tests the source code:

    npm run test-src
  • Tests the example in the example folder:

    npm run test-example
  • Lints the source folder using typescript and eslint:

    npm run lint
  • Builds the typescript code from the ./src folder to javascript code in ./dist:

    npm run build-ts
  • Creates the CLI executable of this program in ./bin/bin.js:

    npm run build-bin

    Make sure that the ./dist exists when you execute this command, otherwise it will not work.

  • Injects in place the generated toc and imported files to README.md:

    npm run build-md
  • Checks the project for spelling mistakes:

    npm run spell-check

    Take a look at the related configuration ./cspell.json.

  • Checks ./src for dead typescript files:

    npm run dead-files

    Take a look at the related configuration ./unimportedrc.json.

Changelog

2.0.3

Removed package name and version from the CLI generated documentation.

2.0.2

Removed the unnecessary quotation marks from the default values in the CLI generated documentation.

2.0.1

bug fixes:

Moved typescript-is from development dependencies to dependencies.

2.0.0

breaking changes:

  • Command line arguments are now evaluated with eval instead of JSON.parse.
  • -v and --version are reserved for printing the version.
  • @private JSDoc tag is now replaced with @cliPrivate.
  • The @CLI JSDoc tag can now get a value as a custom name for the command.

non breaking changes

  • json5 node module is used for parsing package.json and tsconfig.json. That means (among others) no more headaches with trailing commas.
  • You can now add any type you want for command options.
  • The default JSDoc tag value is no longer validated that it is the same type as the argument type.

other

  • README.md has been improved and extra sections like changelog and contributing have been added. You can read the example section code in the README.md now.

1.0.0

  • Published the package to npm.

License

MIT