Coder Social home page Coder Social logo

separaterecords / run-fig Goto Github PK

View Code? Open in Web Editor NEW
3.0 1.0 0.0 203 KB

Build fast (as in, the fastest) command-line apps with JS/TS

Home Page: https://doc.deno.land/https://denopkg.com/SeparateRecords/run-fig/mod.ts

License: MIT License

TypeScript 100.00%
cli command-line deno fig javascript typescript

run-fig's Introduction

Run a Fig spec as a CLI

An experimental JavaScript library (Deno) for building fast command-line tools. In three points:

  • Speed: beats Cliffy Command and Deno's own std/flags in benchmarks
  • Discoverable: once you read the example below, you can figure it out on your own
  • Declarative: define options, args, and subcommands in a simple structure

There's already a repository of over 400 commands built using this schema. It's proven to be extremely easy to write, read, and maintain.


This library is an experiment. It has no type inference, and a very minimal public API.

Use Cliffy if you want to build a production-ready CLI running in Deno right now. It's great!


import Fig from "https://denopkg.com/SeparateRecords/run-fig/mod.ts";

export const spec: Fig.Spec = {
  name: "printfile",
  description: "Print the contents of a file",

  args: {
    name: "path",
    template: "filepaths",
  },

  options: [
    { name: "--stderr", description: "Print on stderr instead of stdout" },
    Fig.help, // opt-in `--help` option
  ],

  subcommands: [
    Fig.helpCommand, // Add `help` command
  ],

  async action({ args: [path], options }) {
    const text = await Deno.readTextFile(path);
    if (options.has("--stderr")) {
      console.error(text);
    } else {
      console.log(text);
    }
    return 0;
  },
};

Fig.run(spec);
$ deno run examples/printfile.ts --help
Print the contents of a file

Usage:
  printfile [flags] <path>

Commands:
  help        Print a help message

Flags:
  --stderr    Print on stderr instead of stdout

Global flags:
  -h, --help  Print a help message

๐Ÿงฑ Args, options, subcommands

  • subcommands are the functions you can invoke
  • args are inputs to your program, like function parameters
  • options are modifiers that let you change how it executes

๐Ÿ“„ The Fig Spec

To make a CLI, you'll make a Fig.Spec. The spec is the top-level command.
Subcommands are the same as a spec, but can have more than one name!

const spec: Fig.Spec = {
  name: "deno",
  options: [
    { name: "--unstable", isPersistent: true },
    Fig.help,
  ],
  subcommands: [
    {
      name: "run",
      args: { name: "command", isVariadic: true },
    },
    {
      name: "doc",
      args: [
        { name: "source" },
        { name: "filter" },
      ],
    }
    Fig.helpCommand,
  ]
}

๐ŸŽฌ Actions

All commands have an action property. When you use a command, it runs the action.

Actions take a bag of properties. These are the most useful, but there are more.

const spec: Fig.Spec = {
  name: "example",
  action({
    args, // Array of arguments
    options, // Methods to retrieve option data
    error, // Print error message
    help, // Generate help text
  }) {
    // ...
  },
};

๐Ÿงช Test your CLI

Fig includes a test suite you can integrate into your Deno tests.

import Fig, { testSpec } from "https://deno.land/x/fig/testing.ts";
import { spec } from "./cli.ts";

Deno.test("CLI spec is valid", testSpec(spec));

๐Ÿƒ Keep your CLI fast as it grows

As you import more complex modules and your module graph grows larger, you'll notice that your program becomes slower to start up over time. This is normal for any JS runtime, but slow startup is a bad user experience!

Dynamic imports solve this. Keep your CLI entrypoint file entirely separate from everything else using dynamic imports in your actions. Your spec file should only top-level import the things you're likely to need immediately (such as spinners, prompts).

import Fig from "./deps/fig.ts";

const spec: Fig.Spec = {
  // ...
  async action() {
    const logic = await import("./src/logic.ts");
    await logic.run();
  },
};

Fig.run(spec);

โณ Future features

There is no timeline for these, but they will be implemented.

  • Built-in, first-class Fig completions
  • Seamless parser-generator
  • Improved type-safety and inference
  • Benchmark data

run-fig's People

Contributors

clo4 avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar

run-fig's Issues

Rethink `testing`

Maybe should be renamed to lints, and more generic (not so tied to Deno, maybe with a Deno adapter)

Type safety

You can use options.get("not an option") and TS won't tell you there's a mistake, because actions currently cannot know their options or args statically.

Blocked on parser generator. Can generate types too.

Add description dedenting for help

Descriptions aren't "dedented" (un-indented) at the moment. There's a proposed String.dedent function, could implement this in the help system.

This would not apply actively, only when formatting the description for help.

Argument and option data types

Blocked on parser generator. Most CLIs only need strings but some have other requirements such as numbers, booleans, files, and enums.

Explain the vision and motivation for the library

The readme explains what the library is and why you should use it, but not why it exists or where it's going. This is critical for contributors -- including myself -- to make it clear what does and doesn't align with project goals

Will put some examples of great OSS/lib vision statements in replies

Decide on a name for the library

"Run Fig" is a placeholder. I intentionally phrased the readme/description to never mention the library's name, partly because:

  • It doesn't have one yet
  • It helps slow growth until it's ready to be used more widely

Deciding on a name is tricky. This isn't an official Fig thing. I do work for Fig, so it could become official (or officially endorsed as a community project), but I don't want to name-squat or do anything out of line.

Host on NPM

Currently this isn't even on deno.land/x but an eventual goal is to host on NPM to use with Bun and Node.

Reimplement help logic

Currently very messy. Critical feature, so did not get cut, but I didn't want to refactor it before launch because it works.

Will spec out behavior too.

Add `Fig.completion` subcommand

This was implemented before release as a proof-of-concept but was cut to due code quality. Will be reimplemented.

Add in one extra line to your subcommands (Fig.completion), then run <cli> completion fig --upload to instantly get powerful completions. Will also support running custom generators on the CLI itself to reuse app logic.

Make it faster

There's a lot of unnecessary slowdown in the analysis stage

Add benchmarks

I've been using benchmarks to test the library the whole time while developing it, but I removed before release. Will re-add with a larger suite.

Parser generator

Fig specs are essentially a grammar definition as JSON. The parser isn't optimal for every CLI because it has to be general enough to run them all, but a parser generator can create the optimal parser for each CLI.

I want this to be seamless. It should feel like no effort at all to set it up for your project. Not sure exactly how this will look right now

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.