Socket
Socket
Sign inDemoInstall

main

Package Overview
Dependencies
1
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.25 to 1.0.0

examples/args.js

12

examples/bare.js
#!/usr/bin/env node
require('../index')(module).run(function($) {
$.cout('foo').exit(); // print with console.out, exit 0
"use strict";
// Run the following file with a "name" flag, --name World
require('../main').run(module, function($) {
// Prints out hello, with the value of the flag name.
// You can optionally attach "exit" at the end with an exit
// code. It defaults to 0.
$.cout('Hello ' + $('name')).exit();
});

16

package.json
{
"name": "main",
"version": "0.0.25",
"main": "index.js",
"description": "Provides useful tools for writing command line scripts",
"version": "1.0.0",
"main": "main.js",
"description": "Document based option parsing.",
"repository": {

@@ -11,8 +11,6 @@ "type": "git",

"keywords": [
"main"
"main", "man", "man page", "options", "flags", "argparse"
],
"dependencies": {
"optimist": "~0.6.1",
"when": "~2.8.0",
"temp": "~0.6.0"
"minimist": "0.0.8"
},

@@ -29,6 +27,4 @@ "scripts": {

"chai": "~1.8.1",
"chai-as-promised": "~4.1.0",
"mocha": "~1.17.0",
"mocha-as-promised": "~2.0.0"
"mocha": "~1.17.0"
}
}

@@ -1,161 +0,157 @@

# node-main
# main
At the most basic level, `node-main` provides an easy way to specify an [entry point](http://en.wikipedia.org/wiki/Entry_point) for a script that is ran on the command line. It allows us to call a block of code *only* when the script is executed from the command line. If the script is `require`'d into another node module, it will not execute the main block.
Document based option parsing.
`node-main` also supports automatic usage generation, and a whole plethora of tools that serve as shortcuts while writing command line scripts.
## Main entry point
The contents of the main function will only be ran when called directly from the command line:
```javascript
// Code out here will always run, as it is outside the main block
console.log('Hello');
// demo.js
exports.foo = function() { return 'bar'; }
require('main')(module)
.usage('./someScript [flags] <firstName> <lastName> <filePath>',
'',
'This simple script will write your first and last name',
'to a file. The middle initial is optional as a flag.')
.flags({
middleInitial: {
alias: 'm', default: '', describe: 'Middle Initial'
}
})
.run(function($) {
// code in this block only runs when called directly from the CLI
$.assert.argsLen(2);
var fullName = $(0) + $('middleInitial') + $(1);
var filePath = $(2);
$.writeSync(filePath, fullName).cout('done!');
require('main').run(module, function($) {
console.log('Hello ' + $('name'));
});
```
Of course, this is only the tip of what's available. Visit the example directories and the documentation for more information
<sub>Note: The [variable `module`](http://nodejs.org/api/modules.html) is required.</sub>
## Installation
## Argument Parsing
npm install --save main
### With no configuration
Don't forget the `--save` flag. It will preserve the version you are using as `node-main` is still going through many changes.
Out of the box, we can get arguments with no configuration. In our first example, `demo.js`, if we were to call it with
## Usage
```bash
./demo.js --name World foo bar baz
```
For more advanced usage information that covers everything, please visit the [full documentation (WIP)](#).
it would print out `"Hello World"`. Positional arguments can be fetched by their position:
### The Basics
You're going to need to require the main module in your script. This is the minumum boilerplate to use `node-main`:
```javascript
require('main')(module).run(function() {
// code here will be executed when ran from the CLI
});
$(0) // "foo"
$(2) // "baz"
```
If you would like to set up usage information and flags, simply add those two before calling run like so:
### With configuration
```javascript
require('main')(module)
.usage(
'./someScript [options] <arg1> <arg2>',
'',
'We can expand this usage information to multiple',
'lines if we want to go into detail of how a ',
'script is to be used.')
.flags({
flagOne: { alias: 'o' },
flagTwo: { boolean: true },
flagThree: { demand: true, description: 'third flag' }
})
.run(function(scriptTools) { // SCRIPT TOOLS
// code here will be executed when ran from the CLI
});
```
There will be no JavaScript options for configuration. Markdown is used instead.
The flags use [`node-optimist`](https://github.com/substack/node-optimist) - so options that are valid there, will be valid in `node-main` (such as demand, boolean, alias, etc.).
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:
Also note that I have included a `scriptTools` variable inside of the run function. This allows us to access the tools that help in writing CLI scripts. For the remainder of *The Basics*, I'll refer to the `scriptTools` variable as "`$`"
```javascript
// the "scriptTools" can be named anything, even $
require('main')(module).run(function($) { /* ... */ });
```
**demo.md**
#### Script Tools
```markdown
# demo -- A demonstration of the features & formatting
Script tools provide shortcuts for repetitive things that come up frequently when writing CLI scripts.
## SYNOPSIS
Visit the [full documentation (WIP)](#) for an exhaustive list of the tools available for use. Visit the example directory to see some in use.
sample [flags] `<first>` `<last>` `[pet]`
**argument/flag fetching**
## OPTIONS
If you wanted to fetch the value for flag 'foo' and get the first positional argument:
### -f, --flag
This is a boolean flag as there is no values that follow the flag.
It can be accessed with $('f') or $('flag')
```javascript
$('foo'); // value of the flag foo
$(0); // the first positional argument
```
### --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.
And array of received arguments can be accessed with `$.args` and an object containing all the flag values can be accessed with `$.flags`.
### -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`.
**printing to the console**
### --default=SOMETHING -d SOMETHING (default=foo)
It is also possible to set default values.
```javascript
$.cout('hello world'); //same as console.log
```
### --home (default=$HOME)
And use environment variables to set those defaults. Any default value
beginning with a `$` will be treated as an environment variable.
Others include `$.cerr` (console.error), `$.out` (process.stdout.write), `$.err` (process.stderr.write).
### --demand (required)
We can also demand that a flag should be set.
**files**
### --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.
There are synchronous and asynchronous versions of all file operations. The sync ones are chainable and can be used in the following fashion:
## AUTHORS
... Another section
```javascript
var file = '/tmp/README.md';
$.cout(
$.writeSync(file, '# Hello World')
.appendSync(file, 'foo bar')
.readSync(file)
);
## BUGS
... Another section. Add as many sections as you want.
```
The async versions use a promise based implementation. The above can be re-written using asynchronously using promises as such:
To use it, specify the path to the markdown document:
```javascript
var file = '/tmp/README.md';
$.write(file, '# Hello World').then(function() {
return $.append(file, 'foo bar');
}).then(function() {
return $.read(file);
}).then($.cout);
require('main').run(module, './demo.md', function($) {
console.log($('default') + ' ' + $('d')); // prints "foo foo"
});
```
A non-exhaustive list of some other file functions (all have async counterparts)
```javascript
$.walkSync
$.existsSync
$.mkdirSync
$.touchSync
$.rmSync
```
<a name="documentation"></a>
## Documentation
There is also a `$.mktemp` function to generate a random file name in the operating systems temporary directory. It doesn't create the file - that's up to you.
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.
**async helpers**
In a nutshell, with our markdown:
There are async helpers such as `$.chain`, `$.sequence`, and many more to help streamline further, but these are well above the basics. Using `$.chain`, the async file example above can be reduced to:
```bash
marked-man demo.md > man/demo.1
```
And then in your `package.json`, reference the man page that was created:
```javascript
$.chain(
[ $.write, file, '# Hello World' ],
[ $.append, file, 'foo bar' ],
[ $.read, file ],
[ $.cout ]
);
{
"name" : "demo",
"version" : "1.2.3",
"description" : "A demo package",
"main" : "demo.js",
"bin": {
"demo": "demo.js"
}
"man" : "./man/doc.1"
}
```
**that's all for now**
When your package is installed globally, the man page will also be installed.
That should be enough to get you started.
### Windows
## Contributing
Use `marked-man --format=html` for html based documentation.
Feel free to add in new features as long as they are accompanied with test cases. Running `npm test` should get you started.
## Extras
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.
### Arguments
- `$.all` - An object containing all the arguments given.
- `$.pos` - An array containing all the positional arguments given.
### IO
- `$.cout()` - Alias for `console.log`, chainable.
- `$.cerr()` - Alias for `console.error`, chainable.
- `$.out` - Alias for `process.stdout`
- `$.err` - Alias for `process.stderr`
## Assert
- `$.assert`
Exports Node's assert library to this variable. Useful for argument checking, argument lengths, etc.
## Misc.
- `$.exit()` - Alias for `process.exit`
"use strict";
var extend = require('util')._extend
, path = require('path')
, fs = require('fs')
, when = require('when')
, sequence = require('when/sequence')
, parallel = require('when/parallel')
, pipeline = require('when/pipeline')
, nodefn = require('when/node/function')
, callbacks = require('when/callbacks');
var extend = require('util')._extend;
// Async Tools
//----------------------------
exports.load = function(argv, markdown) {
var self = {};
exports.exists = function(filePath) {
return callbacks.call(fs.exists, filePath);
};
exports.mkdir = function(directoryPath) {
var split = directoryPath.split(path.sep);
// Handle cases where user specifies root, e.g. /home/nolan/...
if (split[0] == '') {
split.shift();
split[0] = path.sep + split[0];
// Call a function and return self for chaining purposes
function returnSelf(fn) {
return function() {
fn.apply(null, arguments);
return self;
};
}
return when.reduce(split, function(previousPath, itemInPath) {
var newPath = path.join(previousPath, itemInPath);
// Options
var optparser = require('./optparser').parse(argv, markdown);
self.all = optparser.options;
self.pos = optparser.options._;
return exports.exists(newPath).then(function(exists) {
var mkdir = exists
? when.resolve()
: nodefn.call(fs.mkdir, newPath);
return mkdir.then(function() { return newPath; });
});
});
};
// Tools
self.exit = process.exit;
self.out = process.stdout;
self.cout = returnSelf(console.log);
self.err = process.stderr;
self.cerr = returnSelf(console.error);
exports.write = function(filePath, data) {
return nodefn.call(fs.writeFile, filePath, data);
};
// Asserts
self.assert = require('assert'); // standard Node.js assert library
exports.touch = function(filePath) {
return exports.write(filePath, '');
// Extend the option parser's getValue $('') functionality with these tools
return extend(optparser.getValue, self);
};
exports.append = function(filePath, data) {
return nodefn.call(fs.appendFile, filePath, data);
};
exports.read = function(filePath) {
return nodefn.call(fs.readFile, filePath, { encoding: 'utf8' });
};
exports.walk = function(directory, includeDir) {
var results = [];
return when.map(nodefn.call(fs.readdir, directory), function(file) {
file = path.join(directory, file);
return nodefn.call(fs.stat, file).then(function(stat) {
if (stat.isFile()) { return results.push(file); }
if (includeDir) { results.push(file + path.sep); }
return exports.walk(file, includeDir).then(function(fileInDir) {
results = results.concat(fileInDir);
});
});
}).then(function() {
return results;
});
};
exports.rm = function(filePath) {
return nodefn.call(fs.stat, filePath).then(function(stat) {
if (stat.isFile()) { return nodefn.call(fs.unlink, filePath); }
return exports.walk(filePath, true).then(function(files) {
return when.map(files.reverse(), function(file) {
return nodefn.call(fs.stat, file).then(function(stat) {
return stat.isDirectory()
? nodefn.call(fs.rmdir, file)
: nodefn.call(fs.unlink, file);
});
}).then(function() {
return nodefn.call(fs.rmdir, filePath);
});
});
});
};
exports.when = when;
exports.sequence = function() {
var fns = Array.prototype.slice.call(arguments);
return sequence(fns);
};
exports.parallel = function() {
var fns = Array.prototype.slice.call(arguments);
return parallel(fns);
};
exports.pipeline = function() {
var fns = Array.prototype.slice.call(arguments);
return pipeline(fns);
};
/*
called in the form
$.chain(
[ <function name>, <arg 1>, <arg2>, ... ],
[ <function name>, <arg 1>, <arg2>, ... ],
...);
The previous functions value will be passed in to the next function
as the final parameter. This allows us to do things like this:
$.chain(
[ $.read, '/tmp/README.md' ],
[ $.cout ]);
In this example we are reading from a file and printing it's contents to
standard output.
*/
exports.chain = function() {
var fnCallArray = Array.prototype.slice.call(arguments)
, fnCall
, i = fnCallArray.length
, valid;
if (typeof fnCallArray === 'undefined' || i === 0) {
return when.resolve();
}
// verify that things are OK with the passed in array... it is a funky
// mechanism that some may get wrong upon first glance
while (i--) {
fnCall = fnCallArray[i];
valid = typeof fnCall !== 'undefined' &&
fnCall instanceof Array &&
fnCall.length > 0;
if (!valid) {
return when.reject(new Error(
'Invalid format provided to chain! check out the docs'));
}
}
// create the functions that will be handled by when/pipeline
var pipeFns = fnCallArray.map(function(fnCall) {
// pull out the function & any arguments provided
var fn = fnCall[0]
, providedArgs = fnCall.slice(1);
return function() {
// Get the value from the previous promise and append it to the
// provided arguments
var priorValue = Array.prototype.slice.call(arguments)[0];
if (typeof priorValue !== 'undefined') {
providedArgs.push(priorValue);
}
return when(fn.apply(undefined, providedArgs));
};
});
return pipeline(pipeFns);
};

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc