mirror of
https://github.com/chenasraf/massarg.git
synced 2026-05-18 01:39:05 +00:00
prerelease - new bool flag options
This commit is contained in:
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -2,7 +2,7 @@ name: Releases
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
branches: [master, develop]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/pull_requests.yml
vendored
2
.github/workflows/pull_requests.yml
vendored
@@ -2,7 +2,7 @@ name: Pull Requests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
branches: [master, develop]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
"line_length": 100,
|
||||
"tables": false,
|
||||
"code_blocks": false
|
||||
}
|
||||
},
|
||||
"no-inline-html": false
|
||||
}
|
||||
|
||||
152
README.md
152
README.md
@@ -1,11 +1,71 @@
|
||||
# massarg
|
||||
# Massarg
|
||||
|
||||
Massarg is a beautiful, flexible, powerful, and simple-to-use command/argument parser for JS
|
||||
Massarg is a simple-to-use, beautiful, flexible, and powerful command/argument parser for JS
|
||||
applications, allowing you to create complex but easy applications that consume command-line
|
||||
arguments and commands.
|
||||
|
||||
Yes, there are a lot of arg parsers. But hear us out.
|
||||
|
||||
<details>
|
||||
<summary>Table of contents</summary>
|
||||
|
||||
- [Massarg](#massarg)
|
||||
- [Features](#features)
|
||||
- [Usage](#usage)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Installing](#installing)
|
||||
- [Importing](#importing)
|
||||
- [Using](#using)
|
||||
- [Main command](#main-command)
|
||||
- [Example](#example)
|
||||
- [JS/TS](#jsts)
|
||||
- [Shell](#shell)
|
||||
- [Commands](#commands)
|
||||
- [Options](#options)
|
||||
- [Example](#example-1)
|
||||
- [JS/TS](#jsts-1)
|
||||
- [Shell](#shell-1)
|
||||
- [Options](#options-1)
|
||||
- [Options](#options-2)
|
||||
- [Example](#example-2)
|
||||
- [JS/TS](#jsts-2)
|
||||
- [Shell](#shell-2)
|
||||
- [Example Lines](#example-lines)
|
||||
- [Options](#options-3)
|
||||
- [Example](#example-3)
|
||||
- [JS/TS](#jsts-3)
|
||||
- [Help/Usage Command](#helpusage-command)
|
||||
- [Options](#options-4)
|
||||
- [Example](#example-4)
|
||||
- [JS/TS](#jsts-4)
|
||||
- [Shell output](#shell-output)
|
||||
- [Contributing](#contributing)
|
||||
<!-- - [Example](#example) -->
|
||||
<!-- - [JS/TS](#jsts) -->
|
||||
<!-- - [Shell](#shell) -->
|
||||
- [Commands](#commands)
|
||||
- [Options](#options)
|
||||
- [Example](#example-1)
|
||||
- [JS/TS](#jsts-1)
|
||||
- [Shell](#shell-1)
|
||||
- [Options](#options-1)
|
||||
- [Options](#options-2)
|
||||
- [Example](#example-2)
|
||||
- [JS/TS](#jsts-2)
|
||||
- [Shell](#shell-2)
|
||||
- [Example Lines](#example-lines)
|
||||
- [Options](#options-3)
|
||||
- [Example](#example-3)
|
||||
- [JS/TS](#jsts-3)
|
||||
- [Help/Usage Command](#helpusage-command)
|
||||
- [Options](#options-4)
|
||||
- [Example](#example-4)
|
||||
- [JS/TS](#jsts-4)
|
||||
- [Shell output](#shell-output)
|
||||
- [Contributing](#contributing)
|
||||
|
||||
</details>
|
||||
|
||||
## Features
|
||||
|
||||
- Primary command to be run without args
|
||||
@@ -115,12 +175,12 @@ Any arguments that are not taken by options or commands, are automatically passe
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Required | Example | Description |
|
||||
| ------------- | --------------------------- | -------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | `string` | ✅ | `"my-command"` | The name of the command, which will be used in the CLI to trigger it |
|
||||
| `aliases` | `string[]` | | `["m", "mc"]` | Alternate names for the command, available for use in addition to `name` |
|
||||
| `description` | `string` | | `"Description of the command"` | Description for the command, only displayed with `--help` or `printHelp()` |
|
||||
| `run` | `function(options) => void` | ✅ | `(options) => console.log("my-command", options)` | Main function that runs this command. The supplied argument is the options passed via the CLI and parsed by massarg. |
|
||||
| Name (required*) | Type | Example | Description |
|
||||
| ---------------- | --------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name`* | `string` | `"my-command"` | The name of the command, which will be used in the CLI to trigger it |
|
||||
| `aliases` | `string[]` | `["m", "mc"]` | Alternate names for the command, available for use in addition to `name` |
|
||||
| `description` | `string` | `"Description of the command"` | Description for the command, only displayed with `--help` or `printHelp()` |
|
||||
| `run`* | `function(options) => void` | `(options) => console.log("my-command", options)` | Main function that runs this command. The supplied argument is the options passed via the CLI and parsed by massarg. |
|
||||
|
||||
### Example
|
||||
|
||||
@@ -151,7 +211,7 @@ $ ./mybin my-command --my-string "Some string"
|
||||
## Options
|
||||
|
||||
Options are variables you can accept via CLI and parse to use in your commands, e.g. `--my-bool`,
|
||||
`--my-string string`, `--my-number 1`
|
||||
`--no-my-bool`, `--my-string string`, `--my-number 1`
|
||||
|
||||
Any arguments that are not taken by options or commands, are automatically passed to
|
||||
`options.extra`, which you can access when running a command or when using the return value from
|
||||
@@ -159,16 +219,26 @@ Any arguments that are not taken by options or commands, are automatically passe
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Required | Default | Example | Description |
|
||||
| ------------- | --------------------------------- | -------- | -------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name` | `string` | ✅ | | `"my-number"` | The name of the option, which will be used in the CLI to apply it |
|
||||
| `aliases` | `string[]` | | | `["n"]` | Alternate names for the option, available for use in addition to `name` |
|
||||
| `description` | `string` | | | `"Description of the command"` | Description for the command, only displayed with `--help` or `printHelp()` |
|
||||
| `parse` | `function(value, options) => any` | | `String` | `(value, options) => parseInt(value)` | Function that parses this option. The supplied arguments are the string value from the arg, and other options passed via the CLI and parsed by massarg before this one. Not all options will be available. |
|
||||
| `isDefault` | `boolean` | | `false` | | When `true`, any args placed without name will be applied to this option. When more than one arg is supplied this way, only the last given will be used (unless the option is an array type). |
|
||||
| `boolean` | `boolean` | | `false` | | When set to `true`, this option will be treated as a boolean: will accept no value as `true`, or other truthy values as `true`, and the rest as `false` |
|
||||
| `array` | `boolean` | | `false` | | When set to true, you will be able to take multiple values when using the same option more than once. They will all be parsed properly and put into an array. |
|
||||
| `required` | `boolean` | | `false` | | When an option is required, parsing will throw a `RequiredError` if it was not given a proper value. If it is attached to a specific (or several) commands, it will only throw if the relevant command was used. |
|
||||
| Name (required*) | Type | Example | Description |
|
||||
| ------------------------------ | --------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `name`* | `string` | `"my-number"` | The name of the option, which will be used in the CLI to apply it. |
|
||||
| `aliases` | `string[]` | `["n"]` | Alternate names for the option, available for use in addition to `name`. |
|
||||
| `description` | `string` | `"Description of the command"` | Description for the command, only displayed with `--help` or `printHelp()`. |
|
||||
| `parse` (default: `String`) | `function(value, options) => any` | `(value, options) => parseInt(value)` | Function that parses this option. The supplied arguments are the string value from the arg, and other options passed via the CLI and parsed by massarg before this one. Not all options will be available. |
|
||||
| `isDefault` (default: `false`) | `boolean` | | When `true`, any args placed without name will be applied to this option. When more than one arg is supplied this way, only the last given will be used (unless the option is an array type). |
|
||||
| `boolean` (default: `false`) | `boolean` | | When set to `true`, this option will be treated as a boolean: will accept no value as `true`, or other truthy\* values as `true`, and the rest as `false`. They also have special flags that define negation.\*\* |
|
||||
| `array` (default: `false`) | `boolean` | | When set to true, you will be able to take multiple values when using the same option more than once. They will all be parsed properly and put into an array. |
|
||||
| `required` (default: `false`) | `boolean` | | When an option is required, parsing will throw a `RequiredError` if it was not given a proper value. If it is attached to a specific (or several) commands, it will only throw if the relevant command was used. |
|
||||
|
||||
\* In boolean args, truthy values are considered true if they fit one of the following values: `1`,
|
||||
`true`, `yes`, `on`. Anything else is considered falsy.
|
||||
|
||||
\*\* Boolean args will also have special negation flags that allow passing a `false` value by using
|
||||
a variation of the name or alias as a flag and still without supplying a value. The following will
|
||||
work for true, given `name: 'bool', aliases: ['b']`: `--bool`, `-b`, and the following will work for
|
||||
`false`: `--no-bool`, `-!b`. `--bool` and `-b` may still be supplied a truthy/falsy value separately
|
||||
in order to determine their value. Note it might cause unpredicted behavior when combining with
|
||||
options that have default values that are passed directly afterwards.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -214,11 +284,11 @@ atop as titles, if specified.
|
||||
|
||||
### Options
|
||||
|
||||
| Name | Type | Required | Default | Example | Description |
|
||||
| ------------- | -------- | -------- | ------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `input` | `string` | ✅ | | `"my-cmd --number 10"` | The input line, an example of user input that will be displayed as "shell" commands. The prefix is customizable through the `help()` options. |
|
||||
| `output` | `string` | ✅ | | `"you entered my-cmd with the number 10, which is larger than 5"` | The output line, an example of the command's output that will be displayed as "shell" output. The prefix is customizable through the `help()` options. |
|
||||
| `description` | `string` | | | `"Run the my-cmd command with a number parameter"` | An explanation of the input/output that will be display as a title above the input if specified. |
|
||||
| Name (required*) | Type | Default | Example | Description |
|
||||
| ---------------- | -------- | ------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `input`* | `string` | | `"my-cmd --number 10"` | The input line, an example of user input that will be displayed as "shell" commands. The prefix is customizable through the `help()` options. |
|
||||
| `output` | `string` | | `"you entered my-cmd with the number 10, which is larger than 5"` | The output line, an example of the command's output that will be displayed as "shell" output. The prefix is customizable through the `help()` options. |
|
||||
| `description` | `string` | | `"Run the my-cmd command with a number parameter"` | An explanation of the input/output that will be display as a title above the input if specified. |
|
||||
|
||||
### Example
|
||||
|
||||
@@ -281,3 +351,37 @@ massarg().help({
|
||||
#### Shell output
|
||||
|
||||

|
||||
|
||||
## Contributing
|
||||
|
||||
I am developing this package on my free time, so any support, whether code, issues, or just stars
|
||||
is very helpful to sustaining its life. If you would like to donate a bit to help keep the project
|
||||
alive, I would be very thankful!
|
||||
|
||||
<a href='https://ko-fi.com/casraf' target='_blank'>
|
||||
<img height='36' style='border:0px;height:36px;'
|
||||
src='https://cdn.ko-fi.com/cdn/kofi1.png?v=3'
|
||||
alt='Buy Me a Coffee at ko-fi.com' />
|
||||
</a>
|
||||
|
||||
I welcome any issues or pull requests on GitHub. If you find a bug, or would like a new feature,
|
||||
don't hesitate to open an appropriate issue and I will do my best to reply promptly.
|
||||
|
||||
If you are a developer and want to contribute code, here are some starting tips:
|
||||
|
||||
1. Fork this repository
|
||||
2. Run `yarn install`
|
||||
3. Run `yarn develop` to start file watch mode
|
||||
4. Make any changes you would like
|
||||
5. Create tests for your changes
|
||||
6. Update the relevant documentation (readme, code comments, type comments)
|
||||
7. Create a PR on upstream
|
||||
|
||||
Some tips on getting around the code:
|
||||
|
||||
- Use `yarn dev` for development - it runs TypeScript compile in watch mode, allowing you to make
|
||||
changes and immediately be able to try them using `yarn cmd`.
|
||||
- Use `yarn build` to build the output
|
||||
- Use `yarn test` to run tests
|
||||
- While `yarn develop` is running, you may run `yarn sample` (try running with `-h` flag) to see
|
||||
a sample script using massarg, that logs the parsed options with the correct parsers and runners.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "massarg",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.7-pre.1",
|
||||
"description": "Flexible, powerful, and simple command/argument parser for CLI applications",
|
||||
"keywords": [
|
||||
"shell",
|
||||
@@ -16,8 +16,9 @@
|
||||
"license": "Apache",
|
||||
"scripts": {
|
||||
"clean": "rm -rf build",
|
||||
"build": "echo $(pwd); yarn clean && tsc -p tsconfig.build.json && cp package.json README.md build",
|
||||
"build": "yarn clean && tsc -p tsconfig.build.json && cp package.json README.md build",
|
||||
"develop": "tsc --watch",
|
||||
"sample": "node build/sample.js",
|
||||
"test": "jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
21
src/index.ts
21
src/index.ts
@@ -183,16 +183,31 @@ export class Massarg<Options> {
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const arg = args[i]
|
||||
const option = this._options.find((o) => `--${o.name}` === arg || o.aliases?.map((a) => `-${a}`).includes(arg))
|
||||
const option = this._options.find(
|
||||
(o) =>
|
||||
// long format
|
||||
`--${o.name}` === arg ||
|
||||
// short format - boolean negate
|
||||
(o.boolean && `--no-${o.name}` === arg) ||
|
||||
// short format
|
||||
o.aliases?.map((a) => `-${a}`).includes(arg) ||
|
||||
// short format - boolean negate
|
||||
(o.boolean && o.aliases?.map((a) => `-!${a}`).includes(arg))
|
||||
//
|
||||
)
|
||||
|
||||
const mightContainDefaultValue = this._options.some((o) => o.isDefault)
|
||||
|
||||
if (option) {
|
||||
let tempValue: any
|
||||
const hasNextToken = args.length > i + 1
|
||||
const nextTokenIsValue = hasNextToken && !args[i + 1].startsWith("-")
|
||||
const nextTokenIsValue =
|
||||
hasNextToken &&
|
||||
(option.boolean ? mightContainDefaultValue || !args[i + 1].startsWith("-") : !args[i + 1].startsWith("-"))
|
||||
|
||||
if (option.boolean && (!hasNextToken || !nextTokenIsValue)) {
|
||||
// parse boolean args w/o value
|
||||
tempValue = true
|
||||
tempValue = !arg.replace(/^-+/, "").startsWith("!")
|
||||
} else if (!hasNextToken || !nextTokenIsValue) {
|
||||
// non-boolean args with no value
|
||||
throw new TypeError(`Missing value for: ${option.name}`)
|
||||
|
||||
@@ -44,46 +44,67 @@ describe("Options", () => {
|
||||
|
||||
describe("bool", () => {
|
||||
test("should parse bool in correct forms", () => {
|
||||
const opts = {
|
||||
const boolOpt = {
|
||||
name: "bool",
|
||||
aliases: ["b"],
|
||||
boolean: true,
|
||||
} as OptionDef<any, any>
|
||||
const defOpt = {
|
||||
name: "default",
|
||||
aliases: ["d"],
|
||||
isDefault: true,
|
||||
}
|
||||
const numOpt = {
|
||||
name: "num",
|
||||
aliases: ["n"],
|
||||
parse: Number,
|
||||
}
|
||||
|
||||
const noArg = massarg().option(opts).parseArgs(["--bool"])
|
||||
expect(noArg).toHaveProperty("bool", true)
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool"])).toHaveProperty("bool", true)
|
||||
|
||||
const truthyNumArg = massarg().option(opts).parseArgs(["--bool", "1"])
|
||||
expect(truthyNumArg).toHaveProperty("bool", true)
|
||||
// 1/0
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool", "1"])).toHaveProperty("bool", true)
|
||||
expect(massarg().option(boolOpt).option(defOpt).parseArgs(["--bool", "1", "def"])).toHaveProperty("bool", true)
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool", "0"])).toHaveProperty("bool", false)
|
||||
|
||||
const falsyNumArg = massarg().option(opts).parseArgs(["--bool", "0"])
|
||||
expect(falsyNumArg).toHaveProperty("bool", false)
|
||||
// on/off
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool", "on"])).toHaveProperty("bool", true)
|
||||
expect(massarg().option(boolOpt).option(defOpt).parseArgs(["--bool", "on", "def"])).toHaveProperty("bool", true)
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool", "off"])).toHaveProperty("bool", false)
|
||||
|
||||
const truthyStrArg = massarg().option(opts).parseArgs(["--bool", "true"])
|
||||
expect(truthyStrArg).toHaveProperty("bool", true)
|
||||
// true/false
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool", "true"])).toHaveProperty("bool", true)
|
||||
expect(massarg().option(boolOpt).option(defOpt).parseArgs(["--bool", "true", "def"])).toHaveProperty(
|
||||
"bool",
|
||||
true
|
||||
)
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool", "false"])).toHaveProperty("bool", false)
|
||||
|
||||
const truthyStrArg2 = massarg().option(opts).parseArgs(["--bool", "on"])
|
||||
expect(truthyStrArg2).toHaveProperty("bool", true)
|
||||
// yes/no
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool", "yes"])).toHaveProperty("bool", true)
|
||||
expect(massarg().option(boolOpt).option(defOpt).parseArgs(["--bool", "yes", "def"])).toHaveProperty(
|
||||
"bool",
|
||||
true
|
||||
)
|
||||
expect(massarg().option(boolOpt).parseArgs(["--bool", "no"])).toHaveProperty("bool", false)
|
||||
|
||||
const truthyStrArg3 = massarg().option(opts).parseArgs(["--bool", "yes"])
|
||||
expect(truthyStrArg3).toHaveProperty("bool", true)
|
||||
// [none]
|
||||
expect(
|
||||
massarg().option(boolOpt).option(defOpt).option(numOpt).parseArgs(["--bool", "someName"])
|
||||
).toHaveProperty("bool", true)
|
||||
|
||||
const falsyStrArg = massarg().option(opts).parseArgs(["--bool", "false"])
|
||||
expect(falsyStrArg).toHaveProperty("bool", false)
|
||||
expect(
|
||||
massarg().option(boolOpt).option(defOpt).option(numOpt).parseArgs(["--bool", "--num", "1", "someName"])
|
||||
).toHaveProperty("bool", true)
|
||||
|
||||
const falsyStrArg2 = massarg().option(opts).parseArgs(["--bool", "off"])
|
||||
expect(falsyStrArg2).toHaveProperty("bool", false)
|
||||
// [none] - negation
|
||||
expect(
|
||||
massarg().option(boolOpt).option(defOpt).option(numOpt).parseArgs(["--no-bool", "--num", "1", "someName"])
|
||||
).toHaveProperty("bool", true)
|
||||
|
||||
const falsyStrArg3 = massarg().option(opts).parseArgs(["--bool", "no"])
|
||||
expect(falsyStrArg3).toHaveProperty("bool", false)
|
||||
|
||||
const otherStrArg = massarg()
|
||||
.option(opts)
|
||||
.option({
|
||||
name: "other",
|
||||
isDefault: true,
|
||||
})
|
||||
.parseArgs(["--bool", "someName"])
|
||||
expect(otherStrArg).toHaveProperty("bool", true)
|
||||
expect(
|
||||
massarg().option(boolOpt).option(defOpt).option(numOpt).parseArgs(["-!b", "--num", "1", "someName"])
|
||||
).toHaveProperty("bool", true)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user