main
Advanced tools
Comparing version 1.0.1 to 100.0.0
{ | ||
"name": "main", | ||
"version": "1.0.1", | ||
"main": "main.js", | ||
"description": "Document based option parsing.", | ||
"version": "100.0.0+querie.cc", | ||
"main": "src/index.js", | ||
"description": "main entry point", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/trevorsenior/node-main.git" | ||
"url": "https://git.querie.cc/libs/main.git" | ||
}, | ||
"keywords": [ | ||
"main", "man", "man page", "options", "flags", "argparse" | ||
], | ||
"dependencies": { | ||
"minimist": "0.0.8" | ||
}, | ||
"scripts": { | ||
"test": "node_modules/.bin/mocha test" | ||
"test": "tap --reporter spec 'test/**/*.js'", | ||
"test:100": "tap --reporter spec --100 'test/**/*.js'" | ||
}, | ||
"author": "Trevor Senior <trevor@tsenior.com> (http://tsenior.com/)", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/trevorsenior/node-main/issues" | ||
"dependencies": { | ||
"minimist": "^1.2.0", | ||
"ramda": "^0.17.1" | ||
}, | ||
"authors": [ | ||
"Jay Querie <jay@querie.cc> (https://jayquerie.com)" | ||
], | ||
"devDependencies": { | ||
"chai": "~1.8.1", | ||
"mocha": "~1.17.0" | ||
} | ||
"prettier": "^1.14.3", | ||
"tap": "^12.0.1" | ||
}, | ||
"keywords": [ | ||
"main", | ||
"entry point", | ||
"entry-point", | ||
"man", | ||
"man page", | ||
"options", | ||
"flags", | ||
"argparse", | ||
"markdown", | ||
"md" | ||
] | ||
} |
236
README.md
@@ -1,137 +0,206 @@ | ||
# main | ||
main | ||
======================================================================== | ||
Document based option parsing. | ||
Provides a 'main' function that is ran when the script is called | ||
directly (e.g. CLI): | ||
## Main entry point | ||
```javascript | ||
require('main').run(module, ($) => { | ||
/* | ||
[ code to run here ] | ||
*/ | ||
}) | ||
``` | ||
The contents of the main function will only be ran when called directly from the command line: | ||
The above code will NOT run if imported into another module. | ||
```javascript | ||
// demo.js | ||
exports.foo = function() { return 'bar'; } | ||
<sub>Note: The [variable `module`][vm] is required.</sub> | ||
require('main').run(module, function($) { | ||
console.log('Hello ' + $('name')); | ||
}); | ||
[vm]: https://nodejs.org/api/modules.html#modules_the_module_object | ||
Install | ||
------------------------------------------------------------------------ | ||
``` | ||
npm i main --save | ||
``` | ||
<sub>Note: The [variable `module`](http://nodejs.org/api/modules.html) is required.</sub> | ||
TOC | ||
------------------------------------------------------------------------ | ||
## Argument Parsing | ||
* [Example: Getting Started (examples/foobar/*)](#example-getting-started-examplesfoobar) | ||
* [Basic Argument Parsing](#basic-argument-parsing) | ||
* [Advanced Argument Parsing](#advanced-argument-parsing) | ||
* [Example: Advanced Argument Parsing (examples/advanced)](#example-advanced-argument-parsing-examplesadvanced) | ||
* [Doc Generation](#doc-generation) | ||
* [CLI helpers](#cli-helpers) | ||
### With no configuration | ||
Out of the box, we can get arguments with no configuration. In our first example, `demo.js`, if we were to call it with | ||
Example: Getting Started (examples/foobar/*) | ||
------------------------------------------------------------------------ | ||
```bash | ||
./demo.js --name World foo bar baz | ||
Let's take a look at HELLO.js: | ||
```javascript | ||
#!/usr/bin/env node | ||
// HELLO.js | ||
exports.foo = () => 'foo' | ||
exports.bar = () => 'bar' | ||
require('main').run(module, ($) => { | ||
console.log('Hello ' + $('name')); | ||
}) | ||
``` | ||
it would print out `"Hello World"`. Positional arguments can be fetched by their position: | ||
HELLO.js defines two functions, and a function to run if called from | ||
the CLI. The functions `foo` and `bar` can now be included in | ||
other modules. | ||
Let's take a look at FOOBAR.js: | ||
```javascript | ||
$(0) // "foo" | ||
$(2) // "baz" | ||
#!/usr/bin/env node | ||
// FOOBAR.js | ||
const { foo, bar } = require('./HELLO'); | ||
require('main').run(module, () => { | ||
console.log(`${foo()} ${bar()} baz`) | ||
}); | ||
``` | ||
### With configuration | ||
Notice how it requires HELLO.js and pulls out the exposed | ||
functions---easy enough. | ||
There will be no JavaScript options for configuration. Markdown is used instead. | ||
Now let's play around a bit with what we've created: | ||
See the [Documentation](#documentation) section for more information on why. The following document will go over the options that you can use in your application: | ||
```sh | ||
$ ./HELLO.js | ||
Hello undefined | ||
$ ./HELLO.js --name World | ||
Hello World | ||
**demo.md** | ||
$ ./FOOBAR.js | ||
foo bar baz | ||
``` | ||
```markdown | ||
# demo -- A demonstration of the features & formatting | ||
Notice how FOOBAR.js does not execute the main | ||
function within HELLO.js. | ||
## SYNOPSIS | ||
See the next section on how argument parsing works. | ||
sample [flags] `<first>` `<last>` `[pet]` | ||
Basic Argument Parsing | ||
------------------------------------------------------------------------ | ||
## OPTIONS | ||
By default parsing arguments works without configuration. In our first | ||
example, examples/foobar automatically parses the `--name` flag. | ||
### -f, --flag | ||
This is a boolean flag as there is no values that follow the flag. | ||
It can be accessed with $('f') or $('flag') | ||
We did this by using `$('name')` in our code within the main | ||
function. Positional arguments can be fetched by referencing their | ||
position, e.g. `$(0)` or `$(1)` to get the first or second args. | ||
### --anything ANYTHING | ||
This flag expects a value to come after it. It can be a number, a string, | ||
etc. The type will be auto detected and the value of $('anything') will | ||
be that value. | ||
Advanced Argument Parsing | ||
------------------------------------------------------------------------ | ||
### -s "VALUE" --string "VALUE" | ||
Same as above, except that the value placeholder is in quotes meaning | ||
that no type detection is performed, and it is kept as a string. Give | ||
it `000123` and it will remain `000123` vs. converting it to a number | ||
resulting in `123`. | ||
If you want: | ||
### --default=SOMETHING -d SOMETHING (default=foo) | ||
It is also possible to set default values. | ||
* flag aliases, e.g. `-f` & `--foo` to be the same. | ||
* flag types, e.g. enforce 'always string'. | ||
* default flag values from: | ||
- hard-coded defaults. | ||
- environment variables. | ||
* specify required flags | ||
### --home (default=$HOME) | ||
And use environment variables to set those defaults. Any default value | ||
beginning with a `$` will be treated as an environment variable. | ||
You'll have to be okay with one fact: | ||
### --demand (required) | ||
We can also demand that a flag should be set. | ||
* Markdown is used as *configuration* for the above. | ||
### --pghost (required, default=$PGHOST) | ||
Combining required and using environment variables as defaults is a | ||
good way to ensure that the value will be set one way or another. | ||
By enforcing this rule, documentation becomes a key part of the CLI | ||
tool. This allows for some neat things such as automatic man page | ||
support and html doc generation (See [Documentation][d]) for your | ||
CLI tool. It will also keep the tools docs up to date when changes are | ||
made. | ||
## AUTHORS | ||
... Another section | ||
[d]: #doc-generation | ||
## BUGS | ||
... Another section. Add as many sections as you want. | ||
``` | ||
The next section covers an example markdown format that the parser | ||
expects, and how it's used in the 'main' module. | ||
To use it, specify the path to the markdown document: | ||
Example: Advanced Argument Parsing (examples/advanced) | ||
------------------------------------------------------------------------ | ||
Check out the contents of `examples/advanced/demo.md`. | ||
To enable advanced argument parsing using this markdown file, simply | ||
pass the location of a properly formatted markdown document as the | ||
second argument to this module: | ||
**examples/advanced/demo.js** | ||
```javascript | ||
require('main').run(module, './demo.md', function($) { | ||
console.log($('default') + ' ' + $('d')); // prints "foo foo" | ||
/* | ||
[ see: examples/advanced/demo.js ] | ||
*/ | ||
}); | ||
``` | ||
Sample session with the above script enforcing the constraints: | ||
<a name="documentation"></a> | ||
## Documentation | ||
```sh | ||
$ ./demo.js | ||
Error: Missing required option demand | ||
The reason we don't put our flags within our script is so we can use [marked-man](https://github.com/kapouer/marked-man) for man pages & HTML documentation, and have [npm install our man pages](https://www.npmjs.org/doc/json.html#man) automatically. | ||
$ ./demo.js --demand | ||
Error: Missing required option pghost | ||
In a nutshell, with our markdown: | ||
```bash | ||
marked-man demo.md > man/demo.1 | ||
$ PGHOST=localhost ./demo.js --demand hey hey you you | ||
{ _: [ 'hey', 'hey', 'you', 'you' ], | ||
f: false, | ||
flag: false, | ||
home: '/home/jay', | ||
demand: true, | ||
default: 'foo', | ||
d: 'foo', | ||
pghost: 'localhost' } | ||
``` | ||
And then in your `package.json`, reference the man page that was created: | ||
Doc Generation | ||
------------------------------------------------------------------------ | ||
```javascript | ||
{ | ||
"name" : "demo", | ||
"version" : "1.2.3", | ||
"description" : "A demo package", | ||
"main" : "demo.js", | ||
"bin": { | ||
"demo": "demo.js" | ||
} | ||
"man" : "./man/doc.1" | ||
} | ||
``` | ||
This is not a part of the 'main' module. This is a light overview of the | ||
module [`marked-man`][mm] that allows us to easilly generate man pages | ||
and HTML dos for our package using the same exact markdown that | ||
specifies our tools advanced options. | ||
When your package is installed globally, the man page will also be installed. | ||
In short: | ||
### Windows | ||
1. `npm install marked-man --save-dev` | ||
2. `npx marked-man demo.md > man/demo.1` | ||
3. add "man" field to package.json: `"man" : "./man/doc.1"` | ||
Use `marked-man --format=html` for html based documentation. | ||
## Extras | ||
View the [official npm docs on the "man" field][fm] for more | ||
information. | ||
In addition to the argument fetching, a very minimal set of functions & getters have been attached to the `$` object. Some of them are chainable and will be indicated as such. View the example directory for more more information. | ||
View [marked-man][mm] repo for more output formats (HTML, etc.) | ||
[mm]: https://github.com/kapouer/marked-man | ||
[fm]: https://docs.npmjs.com/files/package.json#man | ||
Note that man pages are only installed when the package is installed | ||
globally on a users system and can be accessed as usual. | ||
CLI helpers | ||
------------------------------------------------------------------------ | ||
In addition to the argument fetching, a very minimal set of functions & | ||
getters have been attached to the `$` object. | ||
### Arguments | ||
@@ -153,3 +222,4 @@ | ||
Exports Node's assert library to this variable. Useful for argument checking, argument lengths, etc. | ||
Exports Node's assert library to this variable. Useful for argument | ||
checking, argument lengths, etc. | ||
@@ -156,0 +226,0 @@ ## Misc. |
@@ -1,66 +0,68 @@ | ||
"use strict"; | ||
/* global describe */ | ||
/* global it */ | ||
const path = require("path"); | ||
const tap = require("tap"); | ||
const main = require("../src/index"); | ||
var main = require('../main') | ||
, path = require('path') | ||
, expect = require('chai').expect; | ||
const markdownPath = path.join(__dirname, "files", "everything.md"); | ||
describe('main', function() { | ||
tap.test("fail to run when the module has a parent", t => { | ||
const fakeModule = { parent: "parent" }; | ||
let test = ""; | ||
var markdownPath = path.join(__dirname, 'files', 'everything.md'); | ||
main.run(fakeModule, $ => { | ||
test = "ran"; | ||
}); | ||
describe('run', function() { | ||
it('fail to run when the module has a parent', function(done) { | ||
var fakeModule = { parent: 'parent' }; | ||
var test = ''; | ||
main.run(fakeModule, function($) { | ||
test = 'ran'; | ||
}); | ||
setTimeout(function() { | ||
expect(test).to.equal(''); | ||
done(); | ||
}, 50); | ||
}); | ||
setTimeout(() => { | ||
t.equal(test, ""); | ||
t.end(); | ||
}, 500); | ||
}); | ||
it('should run when module has no parent', function(done) { | ||
var fakeModule = { parent: null }; | ||
var test = ''; | ||
main.run(fakeModule, function($) { | ||
test = 'ran'; | ||
}); | ||
setTimeout(function() { | ||
expect(test).to.equal('ran'); | ||
done(); | ||
}, 50); | ||
}); | ||
tap.test("should run when module has no parent", t => { | ||
const fakeModule = { parent: null }; | ||
let test = ""; | ||
it('should use the given markdown', function(done) { | ||
var fakeModule = { parent: null }; | ||
main.run(fakeModule, markdownPath, function($) { | ||
expect($('default')).to.equal('foo'); | ||
done(); | ||
}); | ||
}); | ||
main.run(fakeModule, function($) { | ||
test = "ran"; | ||
}); | ||
it('should use the given arguments', function(done) { | ||
var fakeModule = { parent: null }; | ||
main.run(fakeModule, ['one', '-x', 'yz' ], function($) { | ||
expect($(0)).to.equal('one'); | ||
expect($('x')).to.equal('yz'); | ||
done(); | ||
}); | ||
}); | ||
setTimeout(() => { | ||
t.equal(test, "ran"); | ||
t.end(); | ||
}, 500); | ||
}); | ||
it('should use the given arguments and markdown', function(done) { | ||
var fakeModule = { parent: null }; | ||
main.run(fakeModule, markdownPath, ['one', '-x', 'yz' ], function($) { | ||
expect($(0)).to.equal('one'); | ||
expect($('x')).to.equal('yz'); | ||
expect($('default')).to.equal('foo'); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
tap.test("should use the given markdown", t => { | ||
const fakeModule = { parent: null }; | ||
main.run(fakeModule, markdownPath, $ => { | ||
t.equal($("default"), "foo"); | ||
t.end(); | ||
}); | ||
}); | ||
tap.test("fails to run if markdown file not found", t => { | ||
const fakeModule = { parent: null }; | ||
let test = ""; | ||
main.run(fakeModule, "invalid-markdown-path.md", $ => { | ||
test = "ran"; | ||
}); | ||
setTimeout(() => { | ||
t.equal(test, ""); | ||
t.end(); | ||
}, 500); | ||
}); | ||
tap.test("fails to run if invalid fn", t => { | ||
const fakeModule = { parent: null }; | ||
let test = ""; | ||
main.run(fakeModule, "invalid-markdown-path.md", void 0); | ||
setTimeout(() => { | ||
t.equal(test, ""); | ||
t.end(); | ||
}, 500); | ||
}); |
@@ -1,422 +0,528 @@ | ||
"use strict"; | ||
/* global describe */ | ||
/* global it */ | ||
const tap = require("tap"); | ||
const parse = require("../src/optparser"); | ||
const { | ||
getSections, | ||
parseFlagSection, | ||
getAttributes, | ||
handleOptions, | ||
parseOptions | ||
} = require("../src/optparser"); | ||
var optparser = require('../optparser') | ||
, expect = require('chai').expect; | ||
tap.test("optparser", t => { | ||
t.test("getSections", t => { | ||
t.test("should pull out the OPTIONS section of the markdown", t => { | ||
const markdown = [ | ||
"# sample -- A demonstration of the features & formatting", | ||
"", | ||
"## SYNOPSIS", | ||
"", | ||
"sample [flags] `<first>` `<last>` `[pet]`", | ||
"", | ||
"## OPTIONS", | ||
"", | ||
"### -f, --flag", | ||
"A simple boolean flag", | ||
"", | ||
"## BUGS", | ||
"", | ||
"GitHub" | ||
].join("\n"); | ||
describe('optparser', function() { | ||
const optionBody = getSections("OPTIONS", 2, markdown); | ||
describe('getSections', function() { | ||
t.same( | ||
optionBody[0], | ||
["## OPTIONS", "", "### -f, --flag", "A simple boolean flag", ""].join( | ||
"\n" | ||
) | ||
); | ||
it('should pull out the OPTIONS section of the markdown', function() { | ||
var markdown = [ | ||
'# sample -- A demonstration of the features & formatting', | ||
'', | ||
'## SYNOPSIS', | ||
'', | ||
'sample [flags] `<first>` `<last>` `[pet]`', | ||
'', | ||
'## OPTIONS', | ||
'', | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'', | ||
'## BUGS', | ||
'', | ||
'GitHub' | ||
].join('\n'); | ||
t.end(); | ||
}); | ||
var optionBody = optparser.getSections('OPTIONS', 2, markdown); | ||
t.test( | ||
"should pull out the OPTIONS section of the markdown (dashes)", | ||
t => { | ||
const markdown = [ | ||
"sample -- A demonstration of the features & formatting", | ||
"======================================================", | ||
"", | ||
"SYNOPSIS", | ||
"--------", | ||
"", | ||
"sample [flags] `<first>` `<last>` `[pet]`", | ||
"", | ||
"OPTIONS", | ||
"-------", | ||
"", | ||
"### -f, --flag", | ||
"A simple boolean flag", | ||
"", | ||
"BUGS", | ||
"----", | ||
"", | ||
"GitHub" | ||
].join("\n"); | ||
expect(optionBody[0]).to.eql([ | ||
'## OPTIONS', | ||
'', | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'' | ||
].join('\n')); | ||
}); | ||
const optionBody = getSections("OPTIONS", 2, markdown); | ||
it('should pull out the OPTIONS section of the markdown (dashes)', function() { | ||
var markdown = [ | ||
'sample -- A demonstration of the features & formatting', | ||
'======================================================', | ||
'', | ||
'SYNOPSIS', | ||
'--------', | ||
'', | ||
'sample [flags] `<first>` `<last>` `[pet]`', | ||
'', | ||
'OPTIONS', | ||
'-------', | ||
'', | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'', | ||
'BUGS', | ||
'----', | ||
'', | ||
'GitHub' | ||
].join('\n'); | ||
t.same( | ||
optionBody[0], | ||
[ | ||
"OPTIONS", | ||
"-------", | ||
"", | ||
"### -f, --flag", | ||
"A simple boolean flag", | ||
"" | ||
].join("\n") | ||
); | ||
var optionBody = optparser.getSections('OPTIONS', 2, markdown); | ||
t.end(); | ||
} | ||
); | ||
expect(optionBody[0]).to.eql([ | ||
'OPTIONS', | ||
'-------', | ||
'', | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'' | ||
].join('\n')); | ||
}); | ||
t.test("should pull out the flag sections from the OPTIONS section", t => { | ||
const markdown = [ | ||
"## OPTIONS", | ||
"", | ||
"### -f, --flag", | ||
"A simple boolean flag", | ||
"", | ||
"### -s NAME, --string=NAME", | ||
"", | ||
"Some sample string.", | ||
"" | ||
].join("\n"); | ||
it('should pull out the flag sections from the OPTIONS section', function() { | ||
var markdown = [ | ||
'## OPTIONS', | ||
'', | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'', | ||
'### -s NAME, --string=NAME', | ||
'', | ||
'Some sample string.', | ||
'' | ||
].join('\n'); | ||
const optionBody = getSections("-.*", 3, markdown); | ||
var optionBody = optparser.getSections('-.*', 3, markdown); | ||
t.same(optionBody, [ | ||
["### -f, --flag", "A simple boolean flag", ""].join("\n"), | ||
["### -s NAME, --string=NAME", "", "Some sample string.", ""].join("\n") | ||
]); | ||
expect(optionBody).to.eql([ | ||
[ | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'' | ||
].join('\n'), | ||
[ | ||
'### -s NAME, --string=NAME', | ||
'', | ||
'Some sample string.', | ||
'' | ||
].join('\n') | ||
]); | ||
}); | ||
}); | ||
t.end(); | ||
}); | ||
describe('parseFlagSection', function() { | ||
t.test("pull top-level sections", t => { | ||
const markdown = [ | ||
"# A", | ||
"", | ||
"top-level section A", | ||
"", | ||
"# B", | ||
"", | ||
"top-level section B", | ||
"", | ||
"## B-sub", | ||
"", | ||
"B sub-section" | ||
].join("\n"); | ||
it('should parse boolean flags', function() { | ||
var section = [ | ||
'### -f, --flag', | ||
'A simple boolean flag' | ||
].join('\n'); | ||
const optionBody = getSections("A", 1, markdown); | ||
var parsed = optparser.parseFlagSection(section); | ||
t.equal(optionBody.length, 1); | ||
t.equal(optionBody[0], ["# A", "", "top-level section A", ""].join("\n")); | ||
expect(parsed).to.eql({ | ||
f: { | ||
alias: 'flag', | ||
type: 'boolean' | ||
} | ||
}); | ||
}); | ||
t.end(); | ||
}); | ||
it('should parse a simple flag', function() { | ||
var section = [ | ||
'### -s NAME, --simple-flag=NAME', | ||
'Some description.' | ||
].join('\n'); | ||
t.end(); | ||
}); | ||
var parsed = optparser.parseFlagSection(section); | ||
t.test("parseFlagSection", t => { | ||
t.test("should parse boolean flags", t => { | ||
const section = ["### -f, --flag", "A simple boolean flag"].join("\n"); | ||
expect(parsed).to.eql({ | ||
s: { | ||
alias: 'simple-flag' | ||
} | ||
}); | ||
}); | ||
const parsed = parseFlagSection(section); | ||
it('should parse a simple flag (required)', function() { | ||
var section = [ | ||
'### --simple=s NAME, -s NAME (required)', | ||
'Some description.' | ||
].join('\n'); | ||
t.same(parsed, { | ||
f: { | ||
alias: "flag", | ||
type: "boolean" | ||
} | ||
}); | ||
var parsed = optparser.parseFlagSection(section); | ||
t.end(); | ||
}); | ||
expect(parsed).to.eql({ | ||
simple: { | ||
required: true, | ||
alias: 's' | ||
} | ||
}); | ||
}); | ||
t.test("should parse a simple flag", t => { | ||
const section = [ | ||
"### -s NAME, --simple-flag=NAME", | ||
"Some description." | ||
].join("\n"); | ||
it('should parse a simple flag (default)', function() { | ||
var section = [ | ||
'### -s NAME, --simple=NAME (default=John)', | ||
'Some description.' | ||
].join('\n'); | ||
const parsed = parseFlagSection(section); | ||
var parsed = optparser.parseFlagSection(section); | ||
t.same(parsed, { | ||
s: { | ||
alias: "simple-flag" | ||
} | ||
}); | ||
expect(parsed).to.eql({ | ||
s: { | ||
default: 'John', | ||
alias: 'simple' | ||
} | ||
}); | ||
}); | ||
t.end(); | ||
}); | ||
it('should parse a simple flag (default, env var)', function() { | ||
process.env.FOOBAR_node_main = 'test'; | ||
var section = [ | ||
'### -s NAME, --simple=NAME (default=$FOOBAR_node_main)', | ||
'Some description.' | ||
].join('\n'); | ||
t.test("should parse a simple flag (required)", t => { | ||
const section = [ | ||
"### --simple=s NAME, -s NAME (required)", | ||
"Some description." | ||
].join("\n"); | ||
var parsed = optparser.parseFlagSection(section); | ||
const parsed = parseFlagSection(section); | ||
expect(parsed).to.eql({ | ||
s: { | ||
default: 'test', | ||
alias: 'simple' | ||
} | ||
}); | ||
}); | ||
t.same(parsed, { | ||
simple: { | ||
required: true, | ||
alias: "s" | ||
} | ||
}); | ||
it('should parse a simple flag (default, env var NOT SET)', function() { | ||
var section = [ | ||
'### -s NAME, --simple=NAME (default=$FOOBAR_node_main_empty)', | ||
'Some description.' | ||
].join('\n'); | ||
t.end(); | ||
}); | ||
var parsed = optparser.parseFlagSection(section); | ||
t.test("should parse a simple flag (default)", t => { | ||
const section = [ | ||
"### -s NAME, --simple=NAME (default=John)", | ||
"Some description." | ||
].join("\n"); | ||
expect(parsed).to.eql({ | ||
s: { | ||
alias: 'simple' | ||
} | ||
}); | ||
}); | ||
const parsed = parseFlagSection(section); | ||
t.same(parsed, { | ||
s: { | ||
default: "John", | ||
alias: "simple" | ||
} | ||
}); | ||
it('should parse a simple flag (default, env var, required)', function() { | ||
process.env.FOOBAR_node_main = 'test'; | ||
var section = [ | ||
'### -s NAME, --simple=NAME (default=$FOOBAR_node_main, required)', | ||
'Some description.' | ||
].join('\n'); | ||
t.end(); | ||
}); | ||
var parsed = optparser.parseFlagSection(section); | ||
t.test("should parse a simple flag (default, env var)", t => { | ||
process.env.foobar = "test"; | ||
const section = [ | ||
"### -s NAME, --simple=NAME (default=$foobar)", | ||
"Some description." | ||
].join("\n"); | ||
expect(parsed).to.eql({ | ||
s: { | ||
default: 'test', | ||
required: true, | ||
alias: 'simple' | ||
} | ||
}); | ||
}); | ||
const parsed = parseFlagSection(section); | ||
it('should parse a simple flag (force raw string)', function() { | ||
var section = [ | ||
'### -s "NAME", --simple="NAME"', | ||
'Some description.' | ||
].join('\n'); | ||
t.same(parsed, { | ||
s: { | ||
default: "test", | ||
alias: "simple" | ||
} | ||
}); | ||
var parsed = optparser.parseFlagSection(section); | ||
t.end(); | ||
}); | ||
expect(parsed).to.eql({ | ||
s: { | ||
alias: 'simple', | ||
type: 'string' | ||
} | ||
}); | ||
}); | ||
t.test("should parse a simple flag (default, env var NOT SET)", t => { | ||
const section = [ | ||
"### -s NAME, --simple=NAME (default=$foobar_empty)", | ||
"Some description." | ||
].join("\n"); | ||
}); | ||
const parsed = parseFlagSection(section); | ||
describe('getAttributes', function() { | ||
it('should convert our attributes into minimist format', function() { | ||
var attributes = optparser.getAttributes({ | ||
aString: { | ||
alias: 's', | ||
default: 'foobar', | ||
type: 'string' | ||
}, | ||
aBoolean: { | ||
type: 'boolean' | ||
}, | ||
isRequired: { | ||
required: true | ||
} | ||
}); | ||
t.same(parsed, { | ||
s: { | ||
alias: "simple" | ||
} | ||
}); | ||
expect(attributes).to.eql({ | ||
string: ['aString'], | ||
boolean: ['aBoolean'], | ||
alias: { | ||
s: 'aString' | ||
}, | ||
default: { | ||
aString: 'foobar' | ||
} | ||
}); | ||
}); | ||
t.end(); | ||
}); | ||
it('should handle empty attributes', function() { | ||
expect(optparser.getAttributes({})).to.eql({ | ||
string: [], | ||
boolean: [], | ||
alias: {}, | ||
default: {} | ||
}); | ||
}); | ||
}); | ||
t.test("should parse a simple flag (default, env var, required)", t => { | ||
process.env.foobar = "test"; | ||
const section = [ | ||
"### -s NAME, --simple=NAME (default=$foobar, required)", | ||
"Some description." | ||
].join("\n"); | ||
describe('handleOptions', function() { | ||
it('should parse empty options', function() { | ||
var parsed = optparser.handleOptions([], {}); | ||
expect(parsed._).to.eql([]); | ||
}); | ||
const parsed = parseFlagSection(section); | ||
it('should parse general options (no argv)', function() { | ||
var parsed = optparser.handleOptions([], { | ||
aString: { | ||
alias: 's', | ||
default: 'foobar', | ||
type: 'string' | ||
} | ||
}); | ||
t.same(parsed, { | ||
s: { | ||
default: "test", | ||
required: true, | ||
alias: "simple" | ||
} | ||
}); | ||
expect(parsed).to.eql({ | ||
_: [], | ||
aString: 'foobar', | ||
s: 'foobar' | ||
}); | ||
}); | ||
t.end(); | ||
}); | ||
it('should parse general options (argv)', function() { | ||
var parsed = optparser.handleOptions([ | ||
'--aString', 'cat', 'hello' | ||
], { | ||
aString: { | ||
alias: 's', | ||
default: 'foobar', | ||
type: 'string' | ||
} | ||
}); | ||
t.test("should parse a simple flag (force raw string)", t => { | ||
const section = [ | ||
'### -s "NAME", --simple="NAME"', | ||
"Some description." | ||
].join("\n"); | ||
expect(parsed).to.eql({ | ||
_: [ 'hello' ], | ||
aString: 'cat', | ||
s: 'cat' | ||
}); | ||
}); | ||
const parsed = parseFlagSection(section); | ||
it('should check for required options', function() { | ||
expect(function() { | ||
optparser.handleOptions([], { | ||
aString: { required: true } | ||
}); | ||
}).to.throw(/Missing required option aString/); | ||
}); | ||
}); | ||
t.same(parsed, { | ||
s: { | ||
alias: "simple", | ||
type: "string" | ||
} | ||
}); | ||
describe('parseOptions', function() { | ||
it('should get options from markdown', function() { | ||
var markdown = [ | ||
'# sample -- A demonstration of the features & formatting', | ||
'', | ||
'## SYNOPSIS', | ||
'', | ||
'sample [flags] `<first>` `<last>` `[pet]`', | ||
'', | ||
'## OPTIONS', | ||
'', | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'', | ||
'### -n NUM, --number NUM', | ||
'A simple number flag', | ||
'', | ||
'### -s "STRING", --string "STRING"', | ||
'A simple string flag', | ||
'', | ||
'### --anything ANYTHING', | ||
'A simple string flag', | ||
'', | ||
'## BUGS', | ||
'', | ||
'GitHub' | ||
].join('\n'); | ||
t.end(); | ||
}); | ||
expect(optparser.parseOptions(markdown)).to.eql({ | ||
f: { alias: 'flag', type: 'boolean' }, | ||
n: { alias: 'number' }, | ||
s: { alias: 'string', type: 'string' }, | ||
anything: {} | ||
}); | ||
}); | ||
t.end(); | ||
}); | ||
it('should return an empty object if no markdown was given', function() { | ||
expect(optparser.parseOptions()).to.eql({}); | ||
}); | ||
}); | ||
t.test("getAttributes", t => { | ||
t.test("should convert our attributes into minimist format", t => { | ||
const attributes = getAttributes({ | ||
aString: { | ||
alias: "s", | ||
default: "foobar", | ||
type: "string" | ||
}, | ||
aBoolean: { | ||
type: "boolean" | ||
}, | ||
isRequired: { | ||
required: true | ||
} | ||
}); | ||
describe('parse', function() { | ||
t.same(attributes, { | ||
string: ["aString"], | ||
boolean: ["aBoolean"], | ||
alias: { | ||
s: "aString" | ||
}, | ||
default: { | ||
aString: "foobar" | ||
} | ||
}); | ||
var markdown = [ | ||
'# sample -- A demonstration of the features & formatting', | ||
'', | ||
'## SYNOPSIS', | ||
'', | ||
'sample [flags] `<first>` `<last>` `[pet]`', | ||
'', | ||
'## OPTIONS', | ||
'', | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'', | ||
'### -n NUM, --number NUM', | ||
'A simple number flag', | ||
'', | ||
'### -s "STRING", --string "STRING"', | ||
'A simple string flag', | ||
'', | ||
'### --anything ANYTHING', | ||
'A simple string flag', | ||
'', | ||
'## BUGS', | ||
'', | ||
'GitHub' | ||
].join('\n'); | ||
t.end(); | ||
}); | ||
t.test("should handle empty attributes", t => { | ||
t.same(getAttributes({}), { | ||
string: [], | ||
boolean: [], | ||
alias: {}, | ||
default: {} | ||
}); | ||
it('should work without arguments', function() { | ||
var parsed = optparser.parse([], markdown); | ||
t.end(); | ||
}); | ||
expect(parsed.getValue('flag')).to.equal(false); | ||
expect(parsed.getValue('f')).to.equal(false); | ||
}); | ||
t.test("should throw on invalid types", t => { | ||
t.throws(() => { | ||
getAttributes({ | ||
aWrongType: { | ||
type: "wrongType" | ||
} | ||
}); | ||
}, /invalid type wrongType/); | ||
it('should take positional and flag values', function() { | ||
var parsed = optparser.parse([ | ||
'-f', | ||
'--number', '000123', | ||
'--string', '000123', | ||
'one', '123' | ||
], markdown); | ||
t.end(); | ||
}); | ||
expect(parsed.getValue('flag')).to.equal(true); | ||
expect(parsed.getValue('number')).to.equal(123); | ||
expect(parsed.getValue('string')).to.equal('000123'); | ||
t.end(); | ||
}); | ||
expect(parsed.getValue(0)).to.equal('one'); | ||
expect(parsed.getValue(1)).to.equal(123); | ||
}); | ||
t.test("handleOptions", t => { | ||
t.test("should parse empty options", t => { | ||
const parsed = handleOptions([], {}); | ||
t.same(parsed._, []); | ||
t.end(); | ||
}); | ||
}); | ||
t.test("should parse undefined options", t => { | ||
const parsed = handleOptions(void 0, {}); | ||
t.same(parsed._, []); | ||
t.end(); | ||
}); | ||
t.test("should parse general options (no argv)", t => { | ||
const parsed = handleOptions([], { | ||
aString: { | ||
alias: "s", | ||
default: "foobar", | ||
type: "string" | ||
} | ||
}); | ||
t.same(parsed, { | ||
_: [], | ||
aString: "foobar", | ||
s: "foobar" | ||
}); | ||
t.end(); | ||
}); | ||
t.test("should parse general options (argv)", t => { | ||
const parsed = handleOptions(["--aString", "cat", "hello"], { | ||
aString: { | ||
alias: "s", | ||
default: "foobar", | ||
type: "string" | ||
} | ||
}); | ||
t.same(parsed, { | ||
_: ["hello"], | ||
aString: "cat", | ||
s: "cat" | ||
}); | ||
t.end(); | ||
}); | ||
t.test("should check for required options", t => { | ||
t.throws(() => { | ||
handleOptions([], { | ||
aString: { required: true } | ||
}); | ||
}, /Missing required option aString/); | ||
t.end(); | ||
}); | ||
t.end(); | ||
}); | ||
t.test("parseOptions", t => { | ||
t.test("should get options from markdown", t => { | ||
const markdown = [ | ||
"# sample -- A demonstration of the features & formatting", | ||
"", | ||
"## SYNOPSIS", | ||
"", | ||
"sample [flags] `<first>` `<last>` `[pet]`", | ||
"", | ||
"## OPTIONS", | ||
"", | ||
"### -f, --flag", | ||
"A simple boolean flag", | ||
"", | ||
"### -n NUM, --number NUM", | ||
"A simple number flag", | ||
"", | ||
'### -s "STRING", --string "STRING"', | ||
"A simple string flag", | ||
"", | ||
"### --anything ANYTHING", | ||
"A simple string flag", | ||
"", | ||
"## BUGS", | ||
"", | ||
"GitHub" | ||
].join("\n"); | ||
t.same(parseOptions(markdown), { | ||
f: { alias: "flag", type: "boolean" }, | ||
n: { alias: "number" }, | ||
s: { alias: "string", type: "string" }, | ||
anything: {} | ||
}); | ||
t.end(); | ||
}); | ||
t.test("should return an empty object if no markdown was given", t => { | ||
t.same(parseOptions(), {}); | ||
t.end(); | ||
}); | ||
t.test("should return empty object if no options section", t => { | ||
const markdown = [ | ||
"# sample -- A demonstration of the features & formatting", | ||
"", | ||
"## SYNOPSIS", | ||
"", | ||
"sample [flags] `<first>` `<last>` `[pet]`", | ||
"", | ||
"## BUGS", | ||
"", | ||
"BubHub" | ||
].join("\n"); | ||
t.same(parseOptions(markdown), {}); | ||
t.end(); | ||
}); | ||
t.end(); | ||
}); | ||
t.test("parse", t => { | ||
const markdown = [ | ||
"# sample -- A demonstration of the features & formatting", | ||
"", | ||
"## SYNOPSIS", | ||
"", | ||
"sample [flags] `<first>` `<last>` `[pet]`", | ||
"", | ||
"## OPTIONS", | ||
"", | ||
"### -f, --flag", | ||
"A simple boolean flag", | ||
"", | ||
"### -n NUM, --number NUM", | ||
"A simple number flag", | ||
"", | ||
'### -s "STRING", --string "STRING"', | ||
"A simple string flag", | ||
"", | ||
"### --anything ANYTHING", | ||
"A simple string flag", | ||
"", | ||
"## BUGS", | ||
"", | ||
"GitHub" | ||
].join("\n"); | ||
t.test("should work without arguments", t => { | ||
const parsed = parse([], markdown); | ||
t.equal(parsed.getValue("flag"), false); | ||
t.equal(parsed.getValue("f"), false); | ||
t.end(); | ||
}); | ||
t.test("should take positional and flag values", t => { | ||
const parsed = parse( | ||
["-f", "--number", "000123", "--string", "000123", "one", "123"], | ||
markdown | ||
); | ||
t.equal(parsed.getValue("flag"), true); | ||
t.equal(parsed.getValue("number"), 123); | ||
t.equal(parsed.getValue("string"), "000123"); | ||
t.equal(parsed.getValue(0), "one"); | ||
t.equal(parsed.getValue(1), 123); | ||
t.end(); | ||
}); | ||
t.test("should error on non-string & non-number inputs", t => { | ||
const parsed = parse( | ||
["-f", "--number", "000123", "--string", "000123", "one", "123"], | ||
markdown | ||
); | ||
t.throws(() => { | ||
parsed.getValue({ foo: "bar" }); | ||
}, "provide a position (number) or a flag (string)"); | ||
t.end(); | ||
}); | ||
t.end(); | ||
}); | ||
t.end(); | ||
}); |
@@ -1,58 +0,67 @@ | ||
"use strict"; | ||
/* global describe */ | ||
/* global it */ | ||
const tap = require("tap"); | ||
const { load } = require("../src/tools"); | ||
var tools = require('../tools') | ||
, expect = require('chai').expect; | ||
tap.test("tools", t => { | ||
const markdown = [ | ||
"# sample -- A demonstration of the features & formatting", | ||
"", | ||
"## SYNOPSIS", | ||
"", | ||
"sample [flags] `<first>` `<last>` `[pet]`", | ||
"", | ||
"## OPTIONS", | ||
"", | ||
"### -f, --flag", | ||
"A simple boolean flag", | ||
"", | ||
"### -n NUM, --number NUM", | ||
"A simple number flag", | ||
"", | ||
'### -s "STRING", --string "STRING"', | ||
"A simple string flag", | ||
"", | ||
"### --anything ANYTHING", | ||
"A simple string flag", | ||
"", | ||
"### --default=SOMETHING, -d SOMETHING (default=foo)", | ||
"", | ||
"## BUGS", | ||
"", | ||
"GitHub" | ||
].join("\n"); | ||
describe('tools', function() { | ||
t.test("load", t => { | ||
t.test("should allow chaining", t => { | ||
const $ = load(["-s", "hello", "one", "two"], markdown); | ||
t.equal(typeof $.cout("").cerr(""), "object"); | ||
t.end(); | ||
}); | ||
var markdown = [ | ||
'# sample -- A demonstration of the features & formatting', | ||
'', | ||
'## SYNOPSIS', | ||
'', | ||
'sample [flags] `<first>` `<last>` `[pet]`', | ||
'', | ||
'## OPTIONS', | ||
'', | ||
'### -f, --flag', | ||
'A simple boolean flag', | ||
'', | ||
'### -n NUM, --number NUM', | ||
'A simple number flag', | ||
'', | ||
'### -s "STRING", --string "STRING"', | ||
'A simple string flag', | ||
'', | ||
'### --anything ANYTHING', | ||
'A simple string flag', | ||
'', | ||
'### --default=SOMETHING, -d SOMETHING (default=foo)', | ||
'', | ||
'## BUGS', | ||
'', | ||
'GitHub' | ||
].join('\n'); | ||
t.test("should be able to grab values", t => { | ||
const $ = load(["-s", "hello", "one", "two"], markdown); | ||
t.equal($("string"), "hello"); | ||
t.equal($("default"), "foo"); | ||
t.same($.pos, ["one", "two"]); | ||
t.end(); | ||
}); | ||
describe('load', function() { | ||
t.test("should assert things alright", t => { | ||
const $ = load(["-s", "hello", "one", "two"], markdown); | ||
$.assert(true); | ||
$.assert.equal(5, 5); | ||
t.end(); | ||
}); | ||
var $ = tools.load(['-s', 'hello', 'one', 'two'], markdown); | ||
t.test("should error when flag has no value with default", t => { | ||
t.throws( | ||
() => load(["-d"], markdown), | ||
"Invalid type for option `default`. Expected type of `String`." | ||
); | ||
t.end(); | ||
}); | ||
it('should allow chaining', function() { | ||
expect(typeof $.cout('').cerr('')).to.equal('object'); | ||
}); | ||
t.end(); | ||
}); | ||
it('should be able to grab values', function() { | ||
expect($('string')).to.equal('hello'); | ||
expect($('default')).to.equal('foo'); | ||
expect($.pos).to.eql(['one', 'two']); | ||
}); | ||
it('should assert things alright', function() { | ||
$.assert(true); | ||
$.assert.equal(5, 5); | ||
}); | ||
}); | ||
t.end(); | ||
}); |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
33273
853
0
228
2
14
3
9
3
+ Addedramda@^0.17.1
+ Addedminimist@1.2.8(transitive)
+ Addedramda@0.17.1(transitive)
- Removedminimist@0.0.8(transitive)
Updatedminimist@^1.2.0