Giter Club home page Giter Club logo

deno-cliffy's Introduction

Latest version popularity Build status Code coverage Discord

Cliffy is a simple and type-safe commandline framework for building complex commandline tools with deno.

Documentation

The documentation is available on cliffy.io.

Modules

  • ansi: Chainable ansi escape sequences.

  • command: Create complex and type-safe commandline tools with build-in input validation, auto generated help, shell completions and more.

  • flags: Parse command line arguments (used by the command module).

  • keycode: Parser ansi key codes.

  • keypress: Listen to keypress events with Promise, AsyncIterator and EventTarget APIs.

  • prompt: Create simple and powerful interactive prompts.

  • table: Create cli tables with border, padding, nested tables, etc...

  • testing: Helper functions for testing.

Contributing

Any kind of contribution is welcome! Please take a look at the contributing guidelines.

License

MIT

deno-cliffy's People

Contributors

0x-jerry avatar aleccool213 avatar andrewthauer avatar avery-pierce avatar c4spar avatar canrau avatar cappyzawa avatar draketdl avatar felixzieger avatar fukekazki avatar iuioiua avatar jotsr avatar jsejcksn avatar kasma1990 avatar kecrily avatar kidonng avatar laqda avatar leodog896 avatar lionel-rowe avatar littletof avatar macklinu avatar marcushultman avatar notfilippo avatar ony-boom avatar rafawalter avatar rbeesley avatar sigwinch28 avatar soundstep avatar svallory avatar takuyaw-w avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

deno-cliffy's Issues

Select.prompt broken on 0.11.1

Screenshot from 2020-07-17 17-37-14

code:

// @ts-nocheck
import { parseFlags, OptionType, InputCLI, Confirm, Select } from './deps.ts';

class OgoneCLI {
  public static async init() {
    parseFlags(Deno.args, {
      flags: [
        {
          name: 'create',
          aliases: ['c', "create"],
          type: OptionType.STRING,
        }
      ],
      parse: (type, option, argument, value) => {
        switch(option.name) {
          case 'create':
            OgoneCLI.promptCreation(value);
          break;
        }
        return value;
      }
    });

  }
  public static async promptCreation(value: string) {
    switch(true) {
      case value && ['comp', 'component', 'c'].includes(value):
        const cssLang: string = await Select.prompt({
          messsage: 'CSS pre-processor ?',
          options: [
            { name: 'Sass', value: 'sass' },
            { name: 'Denolus', value: 'denolus' },
          ]
        });
        console.warn(cssLang);
      break;
    }
  }
}
if (import.meta.main) {
  OgoneCLI.init();
}

Add auto-complete prompt

Hi,

Cliffy prompts look pretty dope but one of the most useful prompts IMO would be the auto-complete prompt (example).

Would you consider adding it?

I tried to port enquirer to Deno (see PR 316) but the discrepancies in the key events APIs make it pretty tough and the maintainer couldn't get a look so I'm stuck. I'm thinking that it may be a better option to have a new strong prompt lib in Deno rather than porting a NodeJS lib with all the complexity it adds (my PR was huge).

Add secret prompt

Add a prompt module for credentials input.

  • characters defaults to *
  • optional with hidden or custom characters

Disable `help` command but not `--help` option

Hi @c4spar and thanks for the awesome work you're doing!

I was wondering if it's possible to disable the help command while keeping the --help option working. I'm using BaseCommand, manually registering the --help option and calling command.help() in the option handler, but I get

[ERROR:COMMAND] No help command registered.

I'd actually need to achieve the same result with the completions command, if it can be.

Thanks!

v0.12.1 Not Available on deno.land

I'm currently getting a 404 when trying to retrieve v0.12.1 from deno land. However, v0.12.0 is available. Did the Deno webhook fail while notifying Deno of the new tag?

Available: https://deno.land/x/[email protected]
Not Found: https://deno.land/x/[email protected]

> deno run https://deno.land/x/[email protected]/command.ts
Download https://deno.land/x/[email protected]/command.ts
error: Import 'https://deno.land/x/[email protected]/command.ts' failed: 404 Not Found

The command class should return literal arguments

The command class and the command action handler should also return the literal arguments array which is return by the parseFlags() method.

deno run file.ts arg1 arg2 -- --flag1 val arg1

const { args, options, cmd, literal } = await new Command()
    // ...
    .parse( [ 'arg1', 'arg2', '--', '--flag1', 'val', 'arg1' ] ); 

console.log( literal ); // <-- [ '--flag1', 'val', 'arg1' ]

Provide also a way to access literal arguments inside a command action handler.

nothing

Context: I would to be able to do:

--opt

and

--opt value

with

.option("--opt <value:string>", "desc")

Why then ?
Because I need to have a default value when --opt is used but this default value cannot be known in advance.

Perhaps in the form of:

.option("--opt <value:string>", "desc", { allowEmpty: true })

Broken special character encoding on Windows Terminal

Windows Terminal supports emoji:

deno run https://deno.land/std/examples/welcome.ts

image

However, cliffy Prompt with emoji prints garbled output instead

import { Input } from "https://deno.land/x/cliffy/prompt/mod.ts";
const name: string = await Input.prompt( {message: `What's your name?`, pointer: 'πŸ¦•' } );
deno run --unstable https://gist.githubusercontent.com/prcdpr/a202eabe338fc47bcc5e1c80b987f974/raw/39ac37c59ad0efc8bb7b03b02225e7eaafde5bd7/cliffy-prompt-emoji.ts

image

Code gist to test can be found here https://gist.github.com/prcdpr/a202eabe338fc47bcc5e1c80b987f974

Refactor default commands

  • Remove default options and commands from Command class and provide an easy way to register them manually.
  • Remove BaseCommand (is not needed if we regiser no default options and comands)
  • Move help generation from HelpCommand to a separate help() method to decouple --help option and HelpCommand.

Solution 1:

await new Command()

    // available in all sub commands (can be overridden in child command's)
    .option( '-h, --help', 'Description ...', { global: true, action: help() } )
    // or implement Option class
    .option( '-h, --help', new HelpOption().global() )

    // available in all sub commands (can be overridden in child command's)
    .command( 'help', new HelpCommand().global() )

    // available only in main command
    .command( 'completions', new CompletionsCommand() )

    .parse();

Solution 2:

Implement .use() method:

await new Command()

    // register help option & command with defaults...
    .use( help() )

    // ... or with custom flag names.
    .use( help( {
        global: true,
        flags: '-h, --help',
        command: 'help'
    } ) )

    // register completions command with default's.
    .use( completions() )

    .parse();

function help( opts? ) {
    return ( cmd: Command ) => {
        cmd.option( '-h, --help', 'Help description.', { global: true, action: help() } )
            .command( 'help', new HelpCommand().global() );
    };
}

function completions( opts? ) {
    return ( cmd: Command ) => {
        cmd.command( 'completions', new CompletionsCommand() )
    };
}

Default value incompatible with depends

Given an option with both depends and default value like so:

await new Command()
    .option( '--flag1', 'flag 1' )
    .option( '--flag2 <val:string>', 'flag 2', {depends: ['flag1'], default: 'example'} )
    .parse( Deno.args );

Cliffy thinks flag2 is always set and complains:

Option --flag2 depends on option: --flag1

whenever flag1 is missing even though flag2 only has its default value set.

"Option --help cannot be combined with other options." : default value interference

Using --foo and --foo-a produces different results when used with -h.

import { Command } from "https://x.nest.land/[email protected]/packages/command/mod.ts";

new Command()
  .option("--foo-a", "foo", { default: true })
  .action((_) => {})
  .parse(Deno.args);

image


import { Command } from "https://x.nest.land/[email protected]/packages/command/mod.ts";

new Command()
  .option("--foo", "foo", { default: true })
  .action((_) => {})
  .parse(Deno.args);

image

Provide a way to access the actual command in action handlers

Provide a way to access the actual command in action handlers espacialy for global option's and command's.

Solution 1

Add new parameter (breaking change):

new Command()
    .option( '-h, --help', 'Description ...', {
        global: true,
        action: ( cmd, options, ...args ) => {
            // in case the global option was called on a child command,
            // {cmd} musst be the child command.
            showHelp( cmd );
        }
    } )
    .action( ( cmd, options, ...args ) => {
            showHelp( cmd );
    } )

Solution 2

Merge cmd and options (if you want to merge the options into another object, you will merge also the command instance):

new Command()
    .option( '-h, --help', 'Description ...', {
        global: true,
        action: ( cmd, ...args ) => {
            showHelp( cmd );
        }
    } )
    .action( ( cmd, ...args ) => {
            showHelp( cmd );
    } )

Solution 3

Bind command to action handler (this binding is ugly):

new Command()
    .option( '-h, --help', 'Description ...', {
        global: true,
        action: function (options, ...args) {
            showHelp( this );
        }
    } )
    .action( function ( options, ...args ) {
            showHelp( this );
    } )

Deno can't import [email protected]

Deno can't access imports like this:

import { ... } from 'https://deno.land/[email protected]/fmt/colors.ts';

This results in an error when trying to run a script that uses cliffy:

Download https://deno.land/[email protected]/fmt/colors.ts
error: Import 'https://deno.land/[email protected]/fmt/colors.ts' failed: 403 Forbidden

Local dev environments are not likely to be affected due to caching; however, running scripts on new machines does display this error.

The official Deno docs do not include the "v" in the import. See https://deno.land/[email protected]/fmt/colors.ts

Updating imports to use a version without the "v" prefix allows the import to work:

import { ... } from 'https://deno.land/[email protected]/fmt/colors.ts';

implement stopEarly

If enabled, all arguments starting from the first non option argument will be interpreted as raw argument. This makes it possible to pass flags as value to an executable without using --.

[Feature Request] Allow `-` for stdin

Using - as a filename to mean stdin.

myCommand --someOptions -
new Command()
  .name("myCommand")
  .option("--someOptions", "desc")
  .option("-", "stdin")
  .action((options: Options) => console.log(options.stdin))
  // or using a Symbol
  .action((options: Options) => console.log(options[cliffy.stdin]))

Like unix commands, such as :

cat -

[Prompt] Pasting Clipboard into Prompt Secret Returns Corrupted Data

First of all, this is an awesome project, and I've been enjoying using it!

While implementing an authentication CLI command, I noticed the value of the password that I was pasting in the console was not being captured correctly into the variable.

Bug Description

When pasting into the console, the value pasted is not equal to the value capture by Cliffy Prompt.

Reproduction Steps

  • Create a script.ts file with the following code:
// script.ts
import { Secret } from "https://raw.githubusercontent.com/c4spar/deno-cliffy/v0.11.2/prompt.ts";

const password = await Secret.prompt({message:"Password:",hidden:true})
console.log(password)
  • Copy 0123456789abcdefghijklmnopqrstuvwxyz to your clipboard.
  • Run the script: deno run --unstable script.ts
  • When prompted for password, paste the clipboard into the console.
  • Expected output: 0123456789abcdefghijklmnopqrstuvwxyz
  • Actual Output: 08gow

Environment information

  • Deno Version: deno 1.2.1
  • Cliffy Version: 0.11.2
  • OS: macOS Catalina v10.15.5
  • Shell: zsh 5.7.1 (x86_64-apple-darwin19.0)

Make return type of parse method generic

The return type of the .parse() method from the Command class should be generic.

interface MyArgs {
    [0]: string;
    [1]?: number;
    arg1: string;
    arg2?: number;
}
interface MyOptions {
    opt1: string;
    opt2?: number;
}

const {options, args} = new Command<MyArgs, MyOptions>()
    .arguments('<arg1:string> [arg2:number]')
    .option('--opt1 <val:string>', 'Option 1', {required: true})
    .option('--opt2 <val:number>', 'Option 2')
    .parse(Deno.args);

// and / or

const {options, args} = new Command()
    .arguments('<arg1:string> [arg2:number]')
    .option('--opt1 <val:string>', 'Option 1', {required: true})
    .option('--opt2 <val:number>', 'Option 2')
    .parse<MyArgs, MyOptions>(Deno.args);

Add support for no value flags

await new Command()
    .option('--test', 'Test description')
    .option('--test2 [val:boolean]', 'Test2 description')
    .parse(['-h']);

Atm both flags have an optional booelan value but only --test2 should have an optional value.
--help should output:

    --test                           - Test description
    --test2  [val:boolean]  - Test2 description

Issue with long "words" in renderCell of table package

Hello Everyone,
there is an issue with the table package where an Error is thrown if the length of a single word in the cell is longer than maxCellWidth. In this case fillLength becomes negative and an error is thrown because .repeat is called with a negative count value.

const words: string = consumeWords( length, cell.toString() );

I assume the solution would be some kind of hard wrap if the word gets longer than maxCellWidth.

Create a command with unkown options

I'd like to make a command that runs a process in Deno.
Kind of like npm run test -- --grep="pattern".

I would then get the args and feed them with Deno.run to another process.

But I can't determine the options in advance, how can I create such command?

Capture OS signals during prompts

I have an application that needs to capture and handle OS signals (SIGINT), but it seems like inputs and Select has hardcoded logic for control+c, ending with a Deno.exit(0). I would like to be able to tell cliffy to not exit immediately, but to give me control to properly clean things up before exiting. I'd be up for making a PR for any solution that is of interest. One idea is to offer a callback option.

IFlags is not included as an import in Command examples

Hi!

First, thanks for the work on this library. I'm new to Deno and TypeScript but have found the API for this lib intuitive as it's similar to command suite libs I've used in other languages.

I got a bit stuck when I implemented an action handler though, as I wasn't sure where to find the IFlags type. I got to it eventually from looking through the codebase but it might be helpful to mention where to find or include that dependency in the examples and docs.

Prompt not working with Deno 1.0.1

Given the following code derived from your examples:

import { Input } from "https://deno.land/x/cliffy/prompt.ts";

const name: string = await Input.prompt(`What's your name?`);
console.log("Your name is", name);

will come up with three errors:

error: TS2322 [ERROR]: Type 'string | undefined' is not assignable to type 'string'.
  Type 'undefined' is not assignable to type 'string'.
const name: string = await Input.prompt(`What's your name?`);
      ~~~~
    at file:///C:/Users/felix/dev/deno/test.ts:3:7

TS2339 [ERROR]: Property 'setRaw' does not exist on type 'typeof Deno'.
    Deno.setRaw( 0, true );
         ~~~~~~
    at https://deno.land/x/cliffy/packages/prompt/lib/read-line.ts:14:10

TS2339 [ERROR]: Property 'setRaw' does not exist on type 'typeof Deno'.
    Deno.setRaw( 0, false );
         ~~~~~~
    at https://deno.land/x/cliffy/packages/prompt/lib/read-line.ts:16:10

Found 3 errors.

I used deno 1.0.1 on Windows.

Return named arguments

At the moment the parse method returns an object with an options object and an args array.

const { options, args } = await new Command()
    .arguments( '<cmd:string> [env:string] [dirs...:string]' )
    .parse(Deno.args);

console.log('cmd:', args[0]);

The command should return an args array with named args:

const { options, args } = await new Command()
    .arguments( '<cmd:string> [env:string] [dirs...:string]' )
    .parse(Deno.args);

console.log('cmd:', args[0]);
console.log('cmd:', args.cmd);

Error on env var highlighting

Using cliffy 0.7.0, when I run any command that shows a help message containing environment variables I get the following error:

error: Uncaught TypeError: Cannot read property 'length' of undefined
            if ( details.name.length > 3 ) {
                              ^
    at HelpCommand.parseArgsDefinition (https://deno.land/x/[email protected]/packages/command/lib/base-command.ts:780:31)
    at HelpCommand.highlight (https://deno.land/x/[email protected]/packages/command/commands/help.ts:214:21)
    at https://deno.land/x/[email protected]/packages/command/commands/help.ts:159:26
    at Array.map (<anonymous>)
    at getEnvVars (https://deno.land/x/[email protected]/packages/command/commands/help.ts:157:25)
    at renderHelp (https://deno.land/x/[email protected]/packages/command/commands/help.ts:86:39)
    at HelpCommand.getHelp (https://deno.land/x/[email protected]/packages/command/commands/help.ts:198:9)
    at HelpCommand.show (https://deno.land/x/[email protected]/packages/command/commands/help.ts:32:45)
    at VrCommand.help (https://deno.land/x/[email protected]/packages/command/lib/base-command.ts:1181:31)
    at Object.action (https://deno.land/x/[email protected]/packages/command/lib/default-command.ts:22:26)

The env variables are declared as as stated in the documentation:

VAR_NAME=<value:string>

It looks like parseArgsDefinition() expects the whole <value:string> type declaration as argument, while envVar.type only contains string.

Add editor prompt

Add a prompt module which opens the default text editor for editing files or string values.

Options:

  • file: File | string
  • content: string
  • maxLength

Cannot use select prompt on Windows

image
The prompt is frozen, pressing on directional keys does nothing

const format: string = await Select.prompt({
    message: "Config format: ",
    options: [
      { name: "YAML", value: "foo" },
      { name: "JSON", value: "bar" },
    ],
  });

Options in variadic arguments

In my particular use case I'd need to accept a variable number of cli arguments (including options) unrelated to cliffy after a series of valid args, for example:

mycmd --myoption mysubcmd myarg other args and --options
                               |
                 cliffy args <-|-> other args

To do this I've been using a variadic argument in mysubcmd

new Command()
  .command('mysubcmd [myarg] [otherArgs...]');

but I didn't take into account that --options could break it

[ERROR:...] Unknown option --options

Do you have any suggestions on how to accomplish this?

Allow `--no-` in option declaration

Currently, it's not possible to create options such as --no-check.
I would like to be able to declare this option because the --check option doesn't make sense in my case.

import { Command } from "https://x.nest.land/[email protected]/command/mod.ts";

new Command()
  .option("--no-check", "desc")
  .action(() => {})
  .parse();
> deno run -A --unstable foo.ts
  [...]
  Error: Unknown option: --no-check

Cannot type the letter "c" with Input prompt

Hey there,

thanks for this pretty amazing module! Unfortunately I encountered this weird bug.

  const email = await Input.prompt(
    {
      message: `What's your email?`
    },
  );

I cannot type an email containing the letter "c" (the c doesn't display).

Platform: mac
Deno: 1.0.0
deno-cliffy: 0.7.1

Support common options shared between subcommands

Given the following configuration:

import { Command } from 'https://deno.land/x/[email protected]/command.ts';

await new Command()
    .option( '--db <database:string>', 'use given db' )
    .command( 'cmd1', new Command()
        .option( '--arg1', 'Arg 1' )
        .action( ( source: string, destination: string ) => {
            console.log( 'cmd1 called' );
        } )
    )
    .command( 'cmd2', new Command()
        .option( '--arg2', 'Arg 2' )
        .action( ( source: string, destination: string ) => {
            console.log( 'cmd2 called' );
        } )
    )
    .parse( Deno.args );

I would expect --db to become a shared option across the cmd1 and cmd2 subcommands. It seems that’s not the way cliffy handles this currently.
Instead, passing --db before the command name aborts with Unknown command: cmd1, passing it after yields Unknown option: --db.

Add an easier way to define nested subcommands.

It should be possible to define nested sub commands via namespaces.

await new command()

    .command( 'command1 [arg]' )
    .description( 'First level sub command' )
    .action( console.log )

    .command( 'command1.command2 [arg]' )
    .description( 'Second level sub command' )
    .action( console.log )

    .parse();

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.