clio-ts
TypeScript icon, indicating that this package has built-in type declarations

0.2.5 • Public • Published

clio-ts

💻 A type-driven command line argument parser, based on io-ts.

A fully-fledged command line argument parser, influenced by Rust's clap, using io-ts for safe type conversions:

🤩 Awesome autocomplete, awesome safeness

🎭 Decode your own custom types from strings

🌲 Nested subcommands, composable API

Basic usage

import { command, parse, single, positional, named, t } from 'clio-ts';
 
const cmd = command({
  name: positional({ type: t.string }),
  greeting: named({
    long: 'greeting',
    short: 'g',
    defaultValue: 'Hello',
    type: single(t.string),
  }),
});
 
const { name, greeting } = parse(cmd, process.argv.slice(2));
 
console.log(`${greeting}${name}!`);

command(arguments)

Creates a CLI command. Returns either a parsing error, or an object where every argument provided gets the value with the correct type, along with a special _ key that contains the "rest" of the positional arguments.

Decoding custom types from strings

Not all command line arguments should be strings. You sometimes want integers, UUIDs, file paths, directories, globs...

Note: this section describes the ReadStream type, implemented in ./src/example/test-types.ts

Let's say we're about to write a cat clone. We want to accept a file to read into stdout. A simple example would be something like:

// my-app.ts
 
import { command, parse, positional, t } from 'clio-ts';
 
const app = command({
  file: positional({ type: t.string, displayName: 'file' }),
});
 
// parse arguments
const parsed = parse(app, process.argv.slice(2));
 
const [{ file }] = parsed;
fs.createReadStream(file).pipe(stdout);

That works okay. But we can do better. What if we had a way to get a Stream in return? This is where clio-ts gets its power from. Custom types with io-ts:

// ReadStream.ts
 
import { t, unimplemented } from 'clio-ts';
 
const ReadStream = new t.Type<
  /* Into a */
  Stream,
  /* From a */
  string
>(
  'ReadStream',
  _ => unimplemented(), // This isn't relevant for one-way casting
  (obj, ctx) => {
    // Check that the value provided is a string
    if (typeof obj !== 'string') {
      return t.failure(obj, ctx, 'This is not a string');
    }
 
    // Create the stream and return it
    const stream = fs.createReadStream(file);
    return t.success(stream);
  },
  _ => unimplemented() // This isn't relevant for one-way casting
);

Now we can use (and share) this type and always get a Stream, instead of carrying the implementation detail around:

// my-app.ts
 
import { command, parse, positional, t } from 'clio-ts';
 
const app = command({
  stream: positional({ type: ReadStream, displayName: 'file' }),
});
 
// parse arguments
const parsed = parse(app, process.argv.slice(2));
 
const [{ stream }] = parsed;
stream.pipe(stdout);

This also provide us the ability to add better error messages and more features/conversions to our programs with ease:

  • We can throw an error when the file is not found
  • We can try to parse the string as a URI and check if the protocol is HTTP, if so - make an HTTP request and return the body stream
  • We can see if the string is -, and when it happens, return process.stdin like many Unix applications

And the best thing about it — everything is encapsulated to an easily tested io-ts type definition, which can be easily shared and reused. Take a look at io-ts-types, for instance, which has types like DateFromISOString, NumberFromString and more!

Development

This project was bootstrapped with TSDX.

Local Development

Below is a list of commands you will probably find useful.

npm start or yarn start

Runs the project in development/watch mode. Your project will be rebuilt upon changes. TSDX has a special logger for you convenience. Error messages are pretty printed and formatted for compatibility VS Code's Problems tab.

Your library will be rebuilt if you make edits.

npm run build or yarn build

Bundles the package to the dist folder. The package is optimized and bundled with Rollup into multiple formats (CommonJS, UMD, and ES Module).

npm test or yarn test

Runs the test watcher (Jest) in an interactive mode. By default, runs tests related to files changed since the last commit.

Readme

Keywords

none

Package Sidebar

Install

npm i clio-ts

Weekly Downloads

0

Version

0.2.5

License

MIT

Unpacked Size

222 kB

Total Files

32

Last publish

Collaborators

  • schlez