Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
bandersnatch
Advanced tools
Super lightweight and friendly CLI framework for Node.js.
🚧 alpha version
yargs
and inquirer
It's built-in TypeScript to provide you with some very handy type hints.
Bandersnatch is not designed to be used as a full CLI framework like oclif, and tries to minimize the assumptions made about your program to make bandersnatch easy and intuitive to work with.
# Add dependency
yarn add bandersnatch
Now create a simple app concat.ts
:
import { program, command } from 'bandersnatch'
const concat = command('concat', 'Concatenate input')
.argument('input', 'List of inputs to concatenate', { variadic: true })
.action((args) => console.log(args.input.join(', '))
program().default(concat).run()
And run with:
$ ts-node concat.ts Hello world
Hello, world
👆 Assuming you have ts-node
installed.
Let's dive right into some more features. This simple app has a single default command which pretty prints JSON input. When invoked without input, it'll show an interactive prompt:
import { program, command } from 'bandersnatch'
const app = program('JSON pretty printer').default(
command()
.argument('json', 'Raw JSON input as string')
.option('color', 'Enables colorized output', { type: 'boolean' })
.action(async (args) => {
const json = JSON.parse(args.json)
args.color
? console.dir(json)
: console.log(JSON.stringify(json, undefined, 4))
})
)
app.runOrRepl()
And run with:
$ ts-node pretty.ts
> [0,1,1,2,3,5]
[
0,
1,
1,
2,
3,
5
]
Now, try typing [0,1,1,2,3,5] --c
and then hit TAB
. 😊
Bandersnatch can also ask a user for input if arguments were not provided on the command line:
import { program, command } from 'bandersnatch'
const cmd = command()
.argument('name', "What's your name?", {
prompt: true,
})
.argument('question', "What's your question?", {
prompt: true,
})
.action((args) => {
console.log(`Hi ${args.name}, the answer to "${args.question}" is 42.`)
})
program('Ask me anything').default(cmd).run()
And run with:
$ ts-node ama.ts --name Joram
? What's your question? What is the meaning of life?
Hi Joram, the answer to "What is the meaning of life?" is 42.
When you omit the --name
part, the program will also prompt for it.
ℹ More examples in the examples directory.
In general, bandersnatch is designed to create twelve-factor apps.
Programs are encouraged to use the following conventions with regards to output, based on the POSIX standard.
Bandersnatch has no built-in method for writing to stdout/stderr. Node.js provides everything you need.
All methods are chainable unless the docs mention otherwise.
program(options)
Creates a new program. Options (object, optional) can contain these keys:
description
(string, optional) is used in --help output.prompt
(string, default: >
) use this prompt prefix when in REPL mode.help
(boolean, default: true) adds help
and --help
to the program which displays program usage information.version
(boolean, default: true) adds version
and --version
to the program which displays program version from package.json.program.description(description)
Sets the program description (string, required) used in --help output.
program.prompt(prompt)
Use this prompt prefix (string, required) when in REPL mode.
program.add(command)
Adds a command to the program.
program().add(command(...))
program.default(command)
Adds a default command to the program. Shorthand for:
program().add(command(...).default())
program.run(command)
Uses process.argv or passed in command (string, optional) to match and execute command. Returns promise.
program()
.add(command(...))
.run()
program.repl()
Start a read-eval-print loop.
program()
.add(command(...))
.repl()
program.runOrRepl()
Invokes run()
if process.argv is set, repl()
otherwise.
program()
.add(command(...))
.runOrRepl()
command(name, options)
Creates a new command.
description
(string, optional) is used in --help output.command.argument(name, options)
Adds a positional argument to the command.
description
(string, optional) is used in --help output.optional
(boolean) makes this argument optional.variadic
(boolean) eagerly take all remaining arguments and parse as an array. Only valid for the last argument.command.option(name, options)
Adds an option to the command.
description
(string, optional) is used in --help output.alias
(string or array of strings) alias(es) for the option key.command.command(command)
Adds a sub-command to the command.
command.default()
Mark command as default. Default commands are executed immediately and don't require a name.
command.action(function)
Function which executes when the command is invoked. Is called with these arguments:
There are many options to bundle your application for distribution. We'll discuss a common pattern.
ℹ An example can be found in the examples/bundle directory.
Init a package.json
if needed:
mkdir echo && cd echo
yarn init
Install dependencies:
yarn add bandersnatch
yarn add typescript pkg --dev
And create an example app in src/cli.ts
:
import { program, command } from 'bandersnatch'
export default program()
.withHelp()
.default(
command('echo', 'Echo something in the terminal')
.argument('words', 'Say some kind words', { variadic: true })
.action(console.log)
)
Building your app with TypeScript is very powerful, but runtime compilation is slow so we compile the code ahead of time.
Add a tsconfig.json
, similar to:
{
"include": ["./src"],
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"lib": ["es2017"],
"declaration": true,
"outDir": "lib",
"rootDir": "src",
"strict": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"moduleResolution": "node"
}
}
Add these scripts to your package.json
:
{
"name": "echo",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
+ "scripts": {
+ "prepublishOnly": "yarn build",
+ "build": "tsc",
+ },
"dependencies": {
"bandersnatch": "^1.0.0-alpha.2"
},
"devDependencies": {
"pkg": "^4.4.2",
"typescript": "^3.7.3"
}
}
And compile now by running yarn build
.
Next, we need to create a simple entry point echo.js
, which can be run with
node:
#!/usr/bin/env node
require('./lib/cli').default.run()
To run your app, users may want to run yarn global add echo
. For this to
work, we need to make a small adjustment to package.json
:
{
"name": "echo",
"version": "1.0.0",
- "main": "index.js",
+ "bin": "echo.js",
+ "files": [
+ "lib"
+ ],
"license": "MIT",
"scripts": {
"prepublishOnly": "yarn build",
"build": "tsc",
},
"dependencies": {
"bandersnatch": "^1.0.0-alpha.2"
},
"devDependencies": {
"pkg": "^4.4.2",
"typescript": "^3.7.3"
}
}
You can now npm publish
.
To create a binary (your app with Node.js bundled), add this script to
package.json
:
{
"name": "echo",
"version": "1.0.0",
"bin": "echo.js",
"files": [
"lib"
],
"license": "MIT",
"scripts": {
"prepublishOnly": "yarn build",
"build": "tsc",
+ "bundle": "yarn build && pkg -t host ."
},
"dependencies": {
"bandersnatch": "^1.0.0-alpha.2"
},
"devDependencies": {
"pkg": "^4.4.2",
"typescript": "^3.7.3"
}
}
👆 Omit -t host
to create binaries for all platforms.
Run yarn bundle
and then ./echo --help
. 💪
Optionally deploy to GitHub, S3, etc. using your preferred CD method if needed.
Contributions are very welcome. Please note this project is in a very early stage and the roadmap is a bit foggy still...
# Clone and install
git clone git@github.com:hongaar/bandersnatch.git
cd bandersnatch
yarn
# Run an example
yarn start examples/simple.ts
Please use conventional commits.
Copyright (c) 2020 Joram van den Boezem. Licensed under the MIT license.
Inspired by vorpal
FAQs
Simple TypeScript CLI / REPL framework
The npm package bandersnatch receives a total of 127 weekly downloads. As such, bandersnatch popularity was classified as not popular.
We found that bandersnatch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.