Skip to content

Creating CLI Apps #2

@lsjroberts

Description

@lsjroberts

At the root of Wool's philosophy are three concepts:

  1. A single, good way to achieve a task
  2. A small number of high quality packages
  3. Sandboxed and secure by default (see Security & Package Authorship #1)

To that end, the wool/terminal package will provide a way to create command line applications from simple single commands to git-style programs with sub-commands and curses / blessed style views.

All applications, be they cli or web-based, will be expected to export a default entry. This is much the same as a main function in many common languages such as C and Python.

Programs

All these programs would automatically support --help and --version, e.g.:

wool run hello/world --version
> 1.0.0

And as per #1 they would require the user to give them permission before being able to perform dangerous actions such as calling functions from wool/fs and similar.

Action

A single action that takes no input from the outside world.

// ~/hello-world/wool.json
{
  "name": "hello/world",
  "entry": "index.ts"
}
// ~/hello-world/index.ts
import * as Terminal from 'wool/terminal';

export default Terminal.action(() => {
  console.log('Hello, World!');
});
wool make ~/hello-world
wool run hello/world
> Hello, World!

Command

A command that can be given arguments and flags.

import { command, arg, flag, required, alias, boolean, string } from 'wool/terminal';

export default Terminal.command({
  args: [
    arg('entry', required()),
  ],
  flags: [
    flag('clean', alias('c'), boolean(false)),
    flag('outDir', alias('o'), string('./dist')),
  ],
  action: (cmd) => {
    if (cmd.clean) {
      // ... clean the `cmd.outDir` ...
    }

    // ... do something with `cmd.entry` ...
  },
});
wool run hello/world ./src/index.ts --outDir ./out

Application

An application that can call off to many commands.

import { application, command } from 'wool/terminal';

export default application({
  commands: {
    one: command({ ... }),
    two: command({ ... }),
  }
})
wool run hello/world one ./src/index.ts --outDir ./out

UI Program

A curses / blessed style view.

import * as Terminal from 'wool/terminal';
import { layout, el, text } from 'wool/ui';

export default Terminal.ui({
  args: [...],
  flags: [...],
  init: (cmd) => {},
  update: (msg, model) => {},
  view: (model) => layout([], el([], text`Hello, World!`)),
})
wool run hello/world

The syntax and functionality of wool/ui is a separate work-in-progress.

Questions

Command argument and flag syntax

Above, I've used a variable args syntax:

flag('clean');
flag('clean', alias('c'), boolean(false))

A strictly FP approach would look like:

boolean(alias(flag('clean'), 'c'), false)

But this is clearly a bit rubbish.

Another alternative would be chained functions, e.g.:

flag('clean').alias('c').boolean(false)

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionIdeas open for discussion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions