Home

Awesome

<p align="center"> <img src="logo.svg" width="200px" align="center" /> <h1 align="center">Soly</h1> </p>

Sol Yellow, it's a CLI not just for Kryptonians. built with zod

Features

Install

yarn add soly

or

pnpm i soly

Command-specific Options

You can attach options to a command.

import { createCLI, path } from 'soly';
const cli = createCLI('cli');

cli.command('rm', (rm) => {
  // path is used to parse and throw error if the path does not exists
  const [dir] = rm.positionals([path()]);
  const { recursive } = rm.flags();
  recursive.alias('r');

  return () => {
    console.log(`remove ${dir.value}${recursive.value ? 'recursively' : ''}`);
  };
});

cli.parse();

Variadic arguments

import { createCLI, string } from 'soly';
const cli = createCLI('cli');

cli.command('rm', (rm) => {
  // string for every positional
  const files = rm.positionals(string(), /* min */ 0, /* max */ 10);
  const { recursive } = rm.flags();
  recursive.alias('r');

  return () => {
    console.log(`Total files ${files.length}`);
  };
});

cli.parse();

Dash in option names

Options in camelCase it's tranformed to kebab-case:

import { createCLI, number, z } from 'soly';

cli.command('fetch', (fetch) => {
  // You can define a type for every value
  const { maxRetries, method } = fetch.named({
    maxRetries: number().min(0).default(3),
    method: z.enum(['http', 'https']).default('http')
  });

  return () => {
    console.log(maxRetries.value); // 4
  };
});

cli.parse(['fetch', '--max-retries', '4']);

In fact --clear-screen and --clearScreen are both mapped to options.clearScreen.

Optional args

Like zod all values are required by default you can make it optional with .optional or with .default

Default Command

Register a command that will be used when no other command is matched.

import { createCLI, number, z } from 'soly';

cli.action(() => {
  return () => {
    console.log('default command'); // 4
  };
});

cli.parse();

Exclusive flags

const cli = createCLI('cli');
cli.command('copy', (copy) => {
  const { serve } = copy.flags();
  const { outFolder } = copy.named({
    outFolder: string().refine(
      () => !serve.value,
      'Output folder cannot be set with serve'
    )
  });

  return () => {
    outFolder.value;
  };
});
cli.parse();