angie-log
Advanced tools
Comparing version 0.9.6 to 0.9.7
@@ -5,2 +5,13 @@ # Change Log | ||
#### [0.9.7] - 2015-08-25 | ||
##### Added/Fixed | ||
- Added the name argument as a **passed argument** to the $LogProvider constructor | ||
- Made class methods for specific log methods | ||
- Validate instantiated log call against declared log level | ||
- Added the ability to set many log levels | ||
- Made all directory references relative to `process.cwd()` | ||
- Added additional documentation | ||
- Fixed/Added tests | ||
- Updated README | ||
#### [0.9.6] - 2015-08-25 | ||
@@ -7,0 +18,0 @@ ##### Changed/Removed |
@@ -5,3 +5,2 @@ // System Modules | ||
import {argv} from 'yargs'; | ||
import {exec} from 'child_process'; | ||
import eslint from 'gulp-eslint'; | ||
@@ -14,5 +13,7 @@ import jscs from 'gulp-jscs'; | ||
import babel from 'gulp-babel'; | ||
import esdoc from 'gulp-esdoc'; | ||
import chalk from 'chalk'; | ||
const SRC = 'src/**/*.js', | ||
const SRC_DIR = 'src', | ||
SRC = `${SRC}/**/*.js`, | ||
TRANSPILED_SRC = 'dist', | ||
@@ -76,8 +77,8 @@ TEST_SRC = 'test/src/**/*.spec.js', | ||
gulp.task('babel', function() { | ||
return gulp.src(SRC).pipe(babel()).pipe(gulp.dest(TRANSPILED_SRC)); | ||
return gulp.src('src/**').pipe(babel()).pipe(gulp.dest('dist')); | ||
}); | ||
gulp.task('esdoc', function(cb) { | ||
exec('esdoc -c esdoc.json', cb); | ||
return gulp.src(SRC_DIR).pipe(esdoc({ destination: DOC_SRC })); | ||
}); | ||
gulp.task('bump', function(cb) { | ||
gulp.task('bump', function() { | ||
const version = argv.version, | ||
@@ -89,2 +90,8 @@ bump = (f) => fs.writeFileSync(f, fs.readFileSync(f, 'utf8').replace( | ||
if (version) { | ||
// Verify that the version is in the CHANGELOG | ||
if (fs.readFileSync('CHANGELOG.md', 'utf8').indexOf(version) === -1) { | ||
throw new Error(bread('Version has no entry in CHANGELOG.md')); | ||
} | ||
bump('bin/angie-log'); | ||
@@ -91,0 +98,0 @@ bump('bin/angie-log-dist'); |
{ | ||
"name": "angie-log", | ||
"version": "0.9.6", | ||
"version": "0.9.7", | ||
"author": "Joe Groseclose <@benderTheCrime>", | ||
@@ -16,4 +16,3 @@ "description": "Standalone terminal and outfile logger designed for the Angie MVC", | ||
"test": "gulp test", | ||
"prepublish": "gulp test", | ||
"postinstall": "gulp babel" | ||
"prepublish": "gulp babel" | ||
}, | ||
@@ -45,5 +44,3 @@ "engines": { | ||
"esdoc": "0.2.2", | ||
"gulp": "3.9.0", | ||
"gulp-babel": "^5.1.0", | ||
"gulp-cli": "0.2.0", | ||
"gulp-esdoc": "0.0.3", | ||
"gulp-eslint": "0.12.0", | ||
@@ -56,9 +53,13 @@ "gulp-istanbul": "0.9.0", | ||
"mocha": "2.2.4", | ||
"simple-mock": "0.3.0", | ||
"yargs": "^3.21.0" | ||
"simple-mock": "0.3.0" | ||
}, | ||
"dependencies": { | ||
"babel": "^5.6.4", | ||
"chalk": "1.0.0" | ||
"babel-core": "^5.8.23", | ||
"chalk": "1.0.0", | ||
"gulp": "3.9.0", | ||
"gulp-babel": "^5.1.0", | ||
"gulp-cli": "0.2.0", | ||
"yargs": "^3.21.0" | ||
} | ||
} |
@@ -13,2 +13,3 @@ ## Angie Log | ||
### Usage | ||
@@ -18,2 +19,3 @@ ```bash | ||
``` | ||
```javascript | ||
@@ -23,12 +25,18 @@ import {default as Log} from 'angie-log'; | ||
// Call a new logger with defaults | ||
let log = new Log({ | ||
outfile: 'log.log', // defaults to p.cwd() + '/angie.log' | ||
file: 'log.log', | ||
timestamp: true, | ||
level: 'debug', // info, debug, warn, error | ||
silent: false | ||
}); | ||
let logger = new Log({ | ||
outfile: 'log.log', // Set the outfile | ||
file: 'log.log', // Equivalent to `outfile` | ||
name: 'test', // Set the name of the logger | ||
timestamp: true, // Controls whether the logfile output has a timestamp | ||
level: 'debug', // Sets a single log level | ||
levels: [ 'info', 'debug' ], // Sets many available log levels | ||
logLevel: 'debug', // Equivalent to `level` | ||
logLevels: [ 'info', 'debug' ], // Equivalent to `levels` | ||
silent: false // Controls whether the log instance should output into the terminal as well | ||
}), | ||
err = new Log('log.log', 'test', true, 'error', false); | ||
// Output to log.log | ||
log.logger('test'); | ||
// Call the loggers with the string "test" | ||
logger.info('test'); | ||
err.error('test'); | ||
@@ -38,2 +46,5 @@ // $setOutfile to change the output file | ||
// $setName to change the name of the logger and what is logged in the outfile | ||
log.$setOutfile('test'); | ||
// $setTimestamp to toggle timestamps in the log output | ||
@@ -55,3 +66,11 @@ log.$setTimestamp(true); | ||
### About | ||
Angie Log is designed as an extremely lightweight logging utility for NodeJS which will: | ||
* Prettify the terminal output using the [Chalk](https://www.npmjs.com/package/chalk "Chalk") package | ||
* Provide utilities for printing useful and informative terminal output | ||
* Create asynchronously written, non-blocking log files to maintain said useful and informative output based on well-defined JS log levels | ||
For a list of Frequently Asked Questions, please see the [FAQ](https://github.com/benderTheCrime/angie-log/blob/master/FAQ.md "FAQ") and the [CHANGELOG](https://github.com/benderTheCrime/angie-log/blob/master/CHANGELOG.md "CHANGELOG") for an up to date list of changes. Contributors to this Project are outlined in the [CONTRIBUTORS](https://github.com/benderTheCrime/angie-log/blob/master/CONTRIBUTORS.md "CONTRIBUTORS") file. | ||
### Angie | ||
Please see the [site](http://benderthecrime.github.io/angie/#/about) for news, a quickstart guide, and documentation and the [CHANGELOG](https://github.com/benderTheCrime/angie-log/blob/master/CHANGELOG.md) for an up to date list of changes. | ||
Please see the [site](http://benderthecrime.github.io/angie/) for news, a quickstart guide, and documentation and the [CHANGELOG](https://github.com/benderTheCrime/angie/blob/master/CHANGELOG.md) for an up to date list of changes. |
@@ -8,18 +8,15 @@ /** | ||
// System Modules | ||
import fs from 'fs'; | ||
import chalk from 'chalk'; | ||
import 'babel-core/node_modules/core-js/modules/es6.array.from'; | ||
import fs from 'fs'; | ||
import chalk, {bold} from 'chalk'; | ||
const p = process, | ||
bold = chalk.bold, | ||
LOG_LEVELS = { | ||
error: 'ERROR', | ||
warn: 'WARN', | ||
debug: 'DEBUG', | ||
info: 'INFO' | ||
}, | ||
DEFAULT_LOG_FILE = `${p.cwd()}/angie.log`; | ||
const CWD = process.cwd(), | ||
LOG_LEVELS = { | ||
error: 'ERROR', | ||
warn: 'WARN', | ||
debug: 'DEBUG', | ||
info: 'INFO' | ||
}, | ||
DEFAULT_LOG_FILE = 'angie.log'; | ||
// Message Array to watch and log | ||
let messages = []; | ||
/** | ||
@@ -41,6 +38,8 @@ * @desc $LogProvider is the only class in the Angie Logging module. This module | ||
* a hash of options to pass the logger | ||
* @param {string} outfile.outfile [param=p.cwd() + '/angie.log'] The file | ||
* @param {string} outfile.outfile [param=process.cwd() + '/angie.log'] The file | ||
* to which messages are logged | ||
* @param {string} outfile.file [param=p.cwd() + '/angie.log'] The file to | ||
* which messages are logged | ||
* @param {string} outfile.file [param=process.cwd() + '/angie.log'] The file to | ||
* which messages are logged. All files will be relative to process.cwd(). | ||
* @param {string} outfile.name The name of the logger to be recorded in the | ||
* log file | ||
* @param {boolean} outfile.timestamp [param=true] Whether or not to include | ||
@@ -54,2 +53,4 @@ * a timestamp in the log output | ||
* level. Possible options: debug, error, info, warn | ||
* @param {string} name The name of the logger to be recorded in the | ||
* log file | ||
* @param {boolean} timestamp [param=true] Whether or not to include a | ||
@@ -62,39 +63,71 @@ * timestamp in the log output | ||
* @access public | ||
* @example new $LogProvider(output.log, true, 'DEBUG', false); | ||
* @example new $LogProvider(output.log, 'test', true, 'DEBUG', false); | ||
*/ | ||
constructor( | ||
outfile = DEFAULT_LOG_FILE, | ||
name = null, | ||
timestamp = true, | ||
level = 'DEBUG', | ||
silent = false | ||
level = [ 'DEBUG' ], | ||
silent = false, | ||
messages = [] | ||
) { | ||
// Account for object arguments | ||
[ this.outfile, this.timestamp, this.level, this.silent ] = | ||
typeof outfile === 'object' ? [ | ||
outfile.hasOwnProperty('outfile') || | ||
outfile.hasOwnProperty('file') ? outfile.outfile || | ||
outfile.file : DEFAULT_LOG_FILE, | ||
outfile.hasOwnProperty('timestamp') ? | ||
outfile.timestamp : timestamp, | ||
outfile.hasOwnProperty('level') || | ||
outfile.hasOwnProperty('logLevel') ? | ||
outfile.level || outfile.logLevel : level, | ||
outfile.hasOwnProperty('silent') ? outfile.silent : silent | ||
] : [ outfile, timestamp, level, silent ]; | ||
[ | ||
this.$$outfile, | ||
this.$$name, | ||
this.$$timestamp, | ||
this.$$silent, | ||
this.$$messages | ||
] = typeof outfile === 'object' ? [ | ||
`${CWD}/${ | ||
outfile.hasOwnProperty('outfile') || outfile.hasOwnProperty('file') ? | ||
removeLeadingSlashes(outfile.outfile || outfile.file) : | ||
DEFAULT_LOG_FILE | ||
}`, | ||
outfile.hasOwnProperty('name') ? outfile.name : name, | ||
outfile.hasOwnProperty('timestamp') ? outfile.timestamp : timestamp, | ||
outfile.hasOwnProperty('silent') ? outfile.silent : silent, | ||
outfile.hasOwnProperty('messages') ? outfile.messages : messages | ||
] : [ | ||
`${CWD}/${removeLeadingSlashes(outfile)}`, | ||
name, | ||
timestamp, | ||
silent, | ||
messages | ||
]; | ||
// Check the log level and make sure it is an acceptable value | ||
this.$setLevel(this.level); | ||
if (typeof outfile === 'object') { | ||
if (outfile.hasOwnProperty('level')) { | ||
level = outfile.level; | ||
} else if (outfile.hasOwnProperty('logLevel')) { | ||
level = outfile.logLevel; | ||
} else if (outfile.hasOwnProperty('levels')) { | ||
level = outfile.levels; | ||
} else if (outfile.hasOwnProperty('logLevels')) { | ||
level = outfile.logLevels; | ||
} | ||
} | ||
// Cast level to an Array if it is a string | ||
level = typeof level === 'string' ? [ level ] : level; | ||
// Make sure we properly set up the level | ||
this.$setLevels(level); | ||
// Backup the original level type | ||
this.$$initialLevel = Array.from(this.$$level); | ||
// Observe the messages array, logging a record each time a message is | ||
// added | ||
let me = this; | ||
Object.observe(messages, function() { | ||
let message = messages.shift(); | ||
Object.observe(this.$$messages, function() { | ||
let message = me.$$messages.shift(); | ||
// Forcibly add a hard return if one does not exist | ||
message = !/.*(\r|\n)/.test(message) ? `${message}\n` : message; | ||
message = !/.*(\r|\n)$/.test(message) ? `${message}\n` : message; | ||
// Write to the output file | ||
fs.appendFile(me.outfile, message); | ||
fs.appendFile(me.$$outfile, message); | ||
}, [ 'add' ]); | ||
@@ -104,31 +137,56 @@ } | ||
/** | ||
* @desc $LogProvider.logger will add a log statement for each call that is | ||
* made. It pushes messages to an asynchronous queue, which will execute as | ||
* messages are added. | ||
* @since 0.0.2 | ||
* @param {string} out The message to add to the log | ||
* @desc Logs an error to an outfile and to the terminal (unless otherwise | ||
* specified). Allows any any arguments. | ||
* @since 0.9.7 | ||
* @access public | ||
* @example new $LogProvider(output.log, true, 'DEBUG', false).logger('test'); | ||
* @example new $LogProvider({ ...args }).error('test'); | ||
*/ | ||
logger(out) { | ||
messages.push( | ||
`[${this.timestamp ? new Date().toString() : ''}] ` + | ||
`${this.level} : ` + out | ||
); | ||
if (this.silent !== true) { | ||
$LogProvider[ this.level.toLowerCase() ](out); | ||
} | ||
return this; | ||
error() { | ||
return this.$$filter('error', ...arguments); | ||
} | ||
/** | ||
* @desc Set the file to which the logger records | ||
* @desc Logs a warning to an outfile and to the terminal (unless otherwise | ||
* specified). Allows any any arguments. | ||
* @since 0.9.7 | ||
* @access public | ||
* @example new $LogProvider({ ...args }).warn('test'); | ||
*/ | ||
warn() { | ||
return this.$$filter('warn', ...arguments); | ||
} | ||
/** | ||
* @desc Logs a debug message to an outfile and to the terminal (unless | ||
* otherwise specified). Allows any any arguments. | ||
* @since 0.9.7 | ||
* @access public | ||
* @example new $LogProvider({ ...args }).debug('test'); | ||
*/ | ||
debug() { | ||
return this.$$filter('debug', ...arguments); | ||
} | ||
/** | ||
* @desc Logs info to an outfile and to the terminal (unless otherwise | ||
* specified) | ||
* @since 0.9.7 | ||
* @access public | ||
* @example new $LogProvider({ ...args }).info('test'); | ||
*/ | ||
info() { | ||
return this.$$filter('info', ...arguments); | ||
} | ||
/** | ||
* @desc Set the file to which the logger records. All files will be | ||
* relative to `process.cwd()`. | ||
* @since 0.0.2 | ||
* @param {string} o [param=p.cwd() + '/angie.log'] The file to which | ||
* messages are logged | ||
* @param {string} o [param=process.cwd() + '/angie.log'] The file to which | ||
* messages are logged. All files will be relative to `process.cwd()`. | ||
* @access private | ||
* @example new $LogProvider().$setlogger('./angie.log'); | ||
*/ | ||
$setOutfile(o = DEFAULT_LOG_FILE) { | ||
this.outfile = o; | ||
$setOutfile(o = 'angie.log') { | ||
this.$$outfile = `${CWD}/${removeLeadingSlashes(o)}`; | ||
return this; | ||
@@ -138,2 +196,18 @@ } | ||
/** | ||
* @desc Set the name of the logger recorded | ||
* @since 0.9.7 | ||
* @param {string} n The name of the logger to be recorded in the log file | ||
* @access private | ||
* @example new $LogProvider().$setName('logger'); | ||
*/ | ||
$setName(n) { | ||
// Check this explicitly to make sure it is not called with an empty | ||
if (n) { | ||
this.$$name = n; | ||
} | ||
return this; | ||
} | ||
/** | ||
* @desc Set the logger timestamp preference | ||
@@ -147,3 +221,3 @@ * @since 0.0.2 | ||
$setTimestamp(t = true) { | ||
this.timestamp = t; | ||
this.$$timestamp = t; | ||
return this; | ||
@@ -161,6 +235,15 @@ } | ||
$setLevel(l) { | ||
l = l || this.level; | ||
this.level = LOG_LEVELS[ | ||
LOG_LEVELS.hasOwnProperty(l) ? l : 'debug' | ||
]; | ||
// Just a little insurance... | ||
if (!(this.$$level instanceof Set)) { | ||
this.$$level = new Set(); | ||
} | ||
// If l exists, check to see if it is a valid log level and set the level | ||
if (l) { | ||
let level = LOG_LEVELS[ | ||
LOG_LEVELS.hasOwnProperty(l) ? l : 'debug' | ||
]; | ||
this.$$level.add(level); | ||
} | ||
return this; | ||
@@ -170,2 +253,25 @@ } | ||
/** | ||
* @desc Set the log level to many level strings | ||
* @since 0.9.8 | ||
* @param {Array} l The recorded log message level array. | ||
* Possible options: debug, error, info, warn | ||
* @access private | ||
* @example new $LogProvider().$setLevels([ 'debug', 'info' ]); | ||
*/ | ||
$setLevels(l) { | ||
let me = this; | ||
// This function only takes an Array of level argument strings | ||
if (l instanceof Array && l.length) { | ||
this.$$level = new Set(); | ||
// Attempt to add the level to the set for each level | ||
l.forEach(function(level) { | ||
me.$setLevel(level); | ||
}); | ||
} | ||
return this; | ||
} | ||
/** | ||
* @desc Set the logger silent preference | ||
@@ -179,3 +285,3 @@ * @since 0.0.2 | ||
$setSilent(s = false) { | ||
this.silent = s; | ||
this.$$silent = s; | ||
return this; | ||
@@ -185,38 +291,86 @@ } | ||
/** | ||
* @desc A wrapper for bold output | ||
* @since 0.0.2 | ||
* @param {string} s One or many string inputs | ||
* @access public | ||
* @example new $LogProvider.bold('test'); | ||
* @desc Checks to see that the specified log level in the instantiated | ||
* logger is observed | ||
* @since 0.9.7 | ||
* @access private | ||
*/ | ||
static bold() { | ||
console.log(bold(...$carriage(...arguments))); | ||
$$filter() { | ||
let level = LOG_LEVELS[ arguments[0] ]; | ||
// Check to see that the log level of the declared logger matches that | ||
// of the called method | ||
if (level && this.$$level.has(level)) { | ||
return this.$$logger.apply(this, arguments); | ||
} | ||
return this; | ||
} | ||
/** | ||
* @desc A wrapper for INFO output | ||
* @desc $LogProvider.prototpye$$logger will add a log statement for each | ||
* call that is made. It pushes messages to an asynchronous queue, which | ||
* will execute as messages are added. Note: if this method is called | ||
* explicitly, the first argument will have to be a valid log level | ||
* @since 0.0.2 | ||
* @param {string} s One or many string inputs | ||
* @access public | ||
* @example new $LogProvider.info('test'); | ||
* @param {string} level The level of log output to put into the log | ||
* @access private | ||
* @example new $LogProvider(output.log, true, 'DEBUG', false).logger('test'); | ||
*/ | ||
static info() { | ||
let args = $carriage(...arguments); | ||
args.unshift(chalk.green(`[${new Date().toString()}] INFO :`)); | ||
args.push('\r'); | ||
console.log(bold.apply(null, args)); | ||
$$logger() { | ||
let args = Array.from(arguments), | ||
level = args.shift(); | ||
if (!LOG_LEVELS.hasOwnProperty(level)) { | ||
$LogProvider.warn( | ||
`${this.$$name ? `[${chalk.cyan(this.$$name)}] ` : ''}$$logger ` + | ||
'called explicitly without a valid log level' | ||
); | ||
return this; | ||
} | ||
// Modify the output string | ||
let message = new Array(args); | ||
message.unshift( | ||
`${this.$$timestamp ? `[${new Date().toString()}] ` : ''}` + | ||
`[${LOG_LEVELS[ level ]}]` + | ||
`${this.$$name ? ` [${this.$$name}]` : ''} :` | ||
); | ||
// Avoid space before return | ||
message = `${message.join(' ')}\r`; | ||
// Push a message to the Array of messages obseved | ||
this.$$messages.push(message); | ||
// Log the message in the terminal as well unless silent | ||
if (this.$$silent !== true) { | ||
$LogProvider[ level ](args); | ||
} | ||
return this; | ||
} | ||
/** | ||
* @desc A wrapper for DEBUG output | ||
* @desc Reset the log level to the original specified log level | ||
* @since 0.9.7 | ||
* @access private | ||
*/ | ||
$$resetLevels() { | ||
return this.$setLevels(this.$$initialLevel); | ||
} | ||
/** | ||
* @desc A wrapper for ERROR output | ||
* @since 0.0.2 | ||
* @param {string} s One or many string inputs | ||
* @access public | ||
* @example new $LogProvider.debug('test'); | ||
* @example new $LogProvider.error('test'); | ||
*/ | ||
static debug() { | ||
let args = $carriage(...arguments); | ||
args.unshift(`[${new Date().toString()}] DEBUG :`); | ||
static error() { | ||
let args = carriage(...arguments); | ||
if (args && args[0].stack) { | ||
args[0] = args[0].stack; | ||
} | ||
args.unshift( | ||
chalk.red(`[${new Date().toString()}] [ERROR] :`)); | ||
args.push('\r'); | ||
console.log(bold.apply(null, args)); | ||
console.error(bold.apply(null, args)); | ||
} | ||
@@ -232,4 +386,4 @@ | ||
static warn() { | ||
let args = $carriage(...arguments); | ||
args.unshift(chalk.yellow(`[${new Date().toString()}] WARN :`)); | ||
let args = carriage(...arguments); | ||
args.unshift(chalk.yellow(`[${new Date().toString()}] [WARN] :`)); | ||
args.push('\r'); | ||
@@ -240,22 +394,36 @@ console.warn(bold.apply(null, args)); | ||
/** | ||
* @desc A wrapper for ERROR output | ||
* @desc A wrapper for DEBUG output | ||
* @since 0.0.2 | ||
* @param {string} s One or many string inputs | ||
* @access public | ||
* @example new $LogProvider.error('test'); | ||
* @example new $LogProvider.debug('test'); | ||
*/ | ||
static error() { | ||
let args = $carriage(...arguments); | ||
if (args && args[0].stack) { | ||
args[0] = args[0].stack; | ||
} | ||
args.unshift( | ||
chalk.red(`[${new Date().toString()}] ERROR :`)); | ||
static debug() { | ||
let args = carriage(...arguments); | ||
args.unshift(`[${new Date().toString()}] [DEBUG] :`); | ||
args.push('\r'); | ||
console.error(bold.apply(null, args)); | ||
console.log(bold.apply(null, args)); | ||
} | ||
/** | ||
* @desc A wrapper for INFO output | ||
* @since 0.0.2 | ||
* @param {string} s One or many string inputs | ||
* @access public | ||
* @example new $LogProvider.info('test'); | ||
*/ | ||
static info() { | ||
let args = carriage(...arguments); | ||
args.unshift(chalk.green(`[${new Date().toString()}] [INFO] :`)); | ||
args.push('\r'); | ||
console.log(bold.apply(null, args)); | ||
} | ||
} | ||
// Helper function to drop hard returns in between arguments | ||
function $carriage() { | ||
/** | ||
* @desc Helper function to drop hard returns in between arguments | ||
* @since 0.0.2 | ||
* @access private | ||
*/ | ||
function carriage() { | ||
let args = Array.prototype.slice.call(arguments); | ||
@@ -265,2 +433,11 @@ return args.map((v) => v.replace ? v.replace(/(\r|\n)/g, ' ') : v); | ||
/** | ||
* @desc Helper function to remove leading argument slashes | ||
* @since 0.9.7 | ||
* @access private | ||
*/ | ||
function removeLeadingSlashes(str) { | ||
return str.replace(/(^(\/))/, ''); | ||
} | ||
export default $LogProvider; |
// System Modules | ||
import fs from 'fs'; | ||
import chalk from 'chalk'; | ||
import chalk, {bold} from 'chalk'; | ||
// Test Modules | ||
import {expect} from 'chai'; | ||
import {expect, assert} from 'chai'; | ||
import simple, {mock} from 'simple-mock'; | ||
@@ -12,4 +12,3 @@ | ||
const p = process, | ||
bold = chalk.bold; | ||
const CWD = process.cwd(); | ||
@@ -20,27 +19,33 @@ describe('$LogProvider', function() { | ||
describe('constructor', function() { | ||
let observeMock; | ||
beforeEach(function() { | ||
mock(Object, 'observe', noop); | ||
observeMock = mock(Object, 'observe', noop); | ||
}); | ||
afterEach(() => simple.restore()); | ||
it('test contructor object arguments', function() { | ||
let log = new Log({ | ||
outfile: 'test', | ||
let logger = new Log({ | ||
outfile: '/test', | ||
name: 'test', | ||
timestamp: false, | ||
level: 'info', | ||
silent: true | ||
silent: true, | ||
messages: [ 'test' ] | ||
}); | ||
expect(Object.observe.calls[0].args[0]).to.deep.eq([]); | ||
expect(Object.observe.calls[0].args[0]).to.deep.eq([ 'test' ]); | ||
expect(Object.observe.calls[0].args[1]).to.be.a.function; | ||
expect(Object.observe.calls[0].args[2]).to.deep.eq([ 'add' ]); | ||
expect(log.outfile).to.eq('test'); | ||
expect(log.timestamp).to.be.false; | ||
expect(log.level).to.eq('INFO'); | ||
expect(log.silent).to.be.true; | ||
expect(logger.$$outfile).to.eq(`${CWD}/test`); | ||
expect(logger.$$name).to.eq('test'); | ||
expect(logger.$$timestamp).to.be.false; | ||
expect(logger.$$level).to.deep.eq(new Set('INFO')); | ||
expect(logger.$$silent).to.be.true; | ||
expect(logger.$$messages).to.deep.eq([ 'test' ]); | ||
expect(logger.$$initialLevel).to.deep.eq([ 'INFO' ]); | ||
}); | ||
it('test constructor object arguments alt names', function() { | ||
let log = new Log({ | ||
file: 'test', | ||
timestamp: false, | ||
logLevel: 'info', | ||
silent: true | ||
let logger = new Log({ | ||
file: '/test', | ||
logLevel: 'info' | ||
}); | ||
@@ -50,168 +55,354 @@ expect(Object.observe.calls[0].args[0]).to.deep.eq([]); | ||
expect(Object.observe.calls[0].args[2]).to.deep.eq([ 'add' ]); | ||
expect(log.outfile).to.eq('test'); | ||
expect(log.timestamp).to.be.false; | ||
expect(log.level).to.eq('INFO'); | ||
expect(log.silent).to.be.true; | ||
expect(logger.$$outfile).to.eq(`${CWD}/test`); | ||
expect(logger.$$level).to.deep.eq(new Set('INFO')); | ||
expect(logger.$$initialLevel).to.deep.eq([ 'INFO' ]); | ||
logger = new Log({ | ||
file: 'test', | ||
levels: [ 'info', 'debug' ] | ||
}); | ||
assert(logger.$$level.has('INFO')); | ||
assert(logger.$$level.has('DEBUG')); | ||
expect(logger.$$initialLevel).to.deep.eq([ 'INFO', 'DEBUG' ]); | ||
logger = new Log({ | ||
file: 'test', | ||
logLevels: [ 'info', 'debug' ] | ||
}); | ||
assert(logger.$$level.has('INFO')); | ||
assert(logger.$$level.has('DEBUG')); | ||
}); | ||
it('test constructor arguments', function() { | ||
let log = new Log('test', false, 'info', true); | ||
expect(Object.observe.calls[0].args[0]).to.deep.eq([]); | ||
let logger = new Log('test', 'test', false, 'info', true, [ 'test' ]); | ||
expect(Object.observe.calls[0].args[0]).to.deep.eq([ 'test' ]); | ||
expect(Object.observe.calls[0].args[1]).to.be.a.function; | ||
expect(Object.observe.calls[0].args[2]).to.deep.eq([ 'add' ]); | ||
expect(log.outfile).to.eq('test'); | ||
expect(log.timestamp).to.be.false; | ||
expect(log.level).to.eq('INFO'); | ||
expect(log.silent).to.be.true; | ||
expect(logger.$$outfile).to.eq(`${CWD}/test`); | ||
expect(logger.$$name).to.eq('test'); | ||
expect(logger.$$timestamp).to.be.false; | ||
expect(logger.$$level).to.deep.eq(new Set('INFO')); | ||
expect(logger.$$silent).to.be.true; | ||
expect(logger.$$messages).to.deep.eq([ 'test' ]); | ||
expect(logger.$$initialLevel).to.deep.eq([ 'INFO' ]); | ||
}); | ||
it('test defaults', function() { | ||
let log = new Log(); | ||
let logger = new Log(); | ||
expect(Object.observe.calls[0].args[0]).to.deep.eq([]); | ||
expect(Object.observe.calls[0].args[1]).to.be.a.function; | ||
expect(Object.observe.calls[0].args[2]).to.deep.eq([ 'add' ]); | ||
expect(log.outfile).to.eq(`${p.cwd()}/angie.log`); | ||
expect(log.timestamp).to.be.true; | ||
expect(log.level).to.eq('DEBUG'); | ||
expect(log.silent).to.be.false; | ||
expect(logger.$$outfile).to.eq(`${CWD}/angie.log`); | ||
expect(logger.$$name).to.be.null; | ||
expect(logger.$$timestamp).to.be.true; | ||
expect(logger.$$level).to.deep.eq(new Set('DEBUG')); | ||
expect(logger.$$silent).to.be.false; | ||
expect(logger.$$messages).to.deep.eq([]); | ||
log = new Log({}); | ||
expect(logger.$$initialLevel).to.deep.eq([ 'DEBUG' ]); | ||
logger = new Log({}); | ||
expect(Object.observe.calls[0].args[0]).to.deep.eq([]); | ||
expect(Object.observe.calls[0].args[1]).to.be.a.function; | ||
expect(Object.observe.calls[0].args[2]).to.deep.eq([ 'add' ]); | ||
expect(log.outfile).to.eq(`${p.cwd()}/angie.log`); | ||
expect(log.timestamp).to.be.true; | ||
expect(log.level).to.eq('DEBUG'); | ||
expect(log.silent).to.be.false; | ||
expect(logger.$$outfile).to.eq(`${CWD}/angie.log`); | ||
expect(logger.$$timestamp).to.be.true; | ||
expect(logger.$$level).to.deep.eq(new Set('DEBUG')); | ||
expect(logger.$$silent).to.be.false; | ||
expect(logger.$$messages).to.deep.eq([]); | ||
expect(logger.$$initialLevel).to.deep.eq([ 'DEBUG' ]); | ||
}); | ||
it('test invalid log level', function() { | ||
expect(new Log({ level: 'test' }).level).to.eq('DEBUG'); | ||
describe('test invalid log levels', function() { | ||
it('test one', function() { | ||
expect( | ||
new Log({ level: 'test' }).$$level | ||
).to.deep.eq(new Set('DEBUG')); | ||
}); | ||
it('test many', function() { | ||
expect( | ||
new Log({ levels: [ 'test', 'nottest' ] }).$$level | ||
).to.deep.eq(new Set('DEBUG')); | ||
}); | ||
}); | ||
describe('Observer calls', function() { | ||
let log; | ||
let logger; | ||
beforeEach(function() { | ||
simple.restore(); | ||
log = new Log({}); | ||
mock(Object, 'observe', function(_, fn) { | ||
fn(); | ||
}); | ||
mock(Date.prototype, 'toString', () => 'test'); | ||
mock(Log, 'debug', noop); | ||
mock(Log, 'error', noop); | ||
mock(fs, 'appendFile', noop); | ||
}); | ||
it('test Observer called with message', function(cb) { | ||
log.logger('test'); | ||
setTimeout(function() { | ||
expect(fs.appendFile.calls[0].args).to.deep.eq( | ||
[ `${p.cwd()}/angie.log`, '[test] DEBUG : test\n' ] | ||
); | ||
cb(); | ||
}, 1000); | ||
it('test Observer called with message', function() { | ||
logger = new Log({ | ||
messages: [ 'test' ] | ||
}); | ||
expect(fs.appendFile.calls[0].args).to.deep.eq( | ||
[ `${CWD}/angie.log`, 'test\n' ] | ||
); | ||
expect(logger.$$messages.length).to.eq(0); | ||
}); | ||
it('test Observer called with message \\r\\n', function(cb) { | ||
log.logger('test\r'); | ||
setTimeout(function() { | ||
expect(fs.appendFile.calls[0].args).to.deep.eq( | ||
[ `${p.cwd()}/angie.log`, '[test] DEBUG : test\r' ] | ||
); | ||
cb(); | ||
}, 100); | ||
it('test Observer called with message \\r\\n', function() { | ||
logger = new Log({ | ||
messages: [ 'test\r' ] | ||
}); | ||
expect(fs.appendFile.calls[0].args).to.deep.eq( | ||
[ `${CWD}/angie.log`, 'test\r' ] | ||
); | ||
expect(logger.$$messages.length).to.eq(0); | ||
}); | ||
}); | ||
}); | ||
describe('logger', function() { | ||
let log; | ||
describe('instance log methods', function() { | ||
let logger; | ||
beforeEach(function() { | ||
mock(Object, 'observe', noop); | ||
mock(Date.prototype, 'toString', () => 'test'); | ||
log = new Log(); | ||
mock(Log, 'debug', noop); | ||
logger = new Log(); | ||
mock(logger, '$$filter', noop); | ||
}); | ||
afterEach(() => simple.restore()); | ||
it('test with timestamp', function() { | ||
expect(log.logger('test')).to.be.an.object; | ||
expect(Log.debug.calls[0].args[0]).to.eq('test'); | ||
it('error', function() { | ||
logger.error('test', 'test'); | ||
expect( | ||
logger.$$filter.calls[0].args | ||
).to.deep.eq([ 'error', 'test', 'test' ]); | ||
}); | ||
it('test without timestamp', function() { | ||
log.$setTimestamp(false); | ||
expect(log.logger('test')).to.be.an.object; | ||
expect(Log.debug.calls[0].args[0]).to.eq('test'); | ||
it('warn', function() { | ||
logger.warn('test', 'test'); | ||
expect( | ||
logger.$$filter.calls[0].args | ||
).to.deep.eq([ 'warn', 'test', 'test' ]); | ||
}); | ||
it('test silent', function() { | ||
log.$setSilent(true); | ||
expect(log.logger('test')).to.be.an.object; | ||
expect(Log.debug).to.not.have.been.called; | ||
it('debug', function() { | ||
logger.debug('test', 'test'); | ||
expect( | ||
logger.$$filter.calls[0].args | ||
).to.deep.eq([ 'debug', 'test', 'test' ]); | ||
}); | ||
it('info', function() { | ||
logger.info('test', 'test'); | ||
expect( | ||
logger.$$filter.calls[0].args | ||
).to.deep.eq([ 'info', 'test', 'test' ]); | ||
}); | ||
}); | ||
describe('$setOutfile', function() { | ||
let log; | ||
let logger; | ||
beforeEach(function() { | ||
log = new Log(); | ||
logger = new Log(); | ||
}); | ||
it('test called without an argument', function() { | ||
log.outfile = ''; | ||
expect(log.$setOutfile()).to.be.an.object; | ||
expect(log.outfile).to.eq(`${p.cwd()}/angie.log`); | ||
logger.$$outfile = ''; | ||
expect(logger.$setOutfile()).to.be.an.object; | ||
expect(logger.$$outfile).to.eq(`${CWD}/angie.log`); | ||
}); | ||
it('test called with an argument', function() { | ||
log.outfile = ''; | ||
expect(log.$setOutfile('test')).to.be.an.object; | ||
expect(log.outfile).to.eq('test'); | ||
logger.$$outfile = ''; | ||
expect(logger.$setOutfile('test')).to.be.an.object; | ||
expect(logger.$$outfile).to.eq(`${CWD}/test`); | ||
}); | ||
}); | ||
describe('$setName', function() { | ||
let logger; | ||
beforeEach(function() { | ||
logger = new Log(); | ||
}); | ||
it('test called without an argument', function() { | ||
expect(logger.$setName()).to.be.an.object; | ||
expect(logger.$$name).to.be.null; | ||
}); | ||
it('test called with an argument', function() { | ||
expect(logger.$setName('test')).to.be.an.object; | ||
expect(logger.$$name).to.eq('test'); | ||
}); | ||
}); | ||
describe('$setTimestamp', function() { | ||
let log; | ||
let logger; | ||
beforeEach(function() { | ||
log = new Log(); | ||
logger = new Log(); | ||
}); | ||
it('test called without an argument', function() { | ||
log.timestamp = ''; | ||
expect(log.$setTimestamp()).to.be.an.object; | ||
expect(log.timestamp).to.be.true; | ||
logger.$$timestamp = ''; | ||
expect(logger.$setTimestamp()).to.be.an.object; | ||
expect(logger.$$timestamp).to.be.true; | ||
}); | ||
it('test called with an argument', function() { | ||
log.timestamp = ''; | ||
expect(log.$setTimestamp(false)).to.be.an.object; | ||
expect(log.timestamp).to.be.false; | ||
logger.$$timestamp = ''; | ||
expect(logger.$setTimestamp(false)).to.be.an.object; | ||
expect(logger.$$timestamp).to.be.false; | ||
}); | ||
}); | ||
describe('$setLevel', function() { | ||
let log; | ||
let logger; | ||
beforeEach(function() { | ||
log = new Log(); | ||
logger = new Log(); | ||
}); | ||
it('test called without an argument', function() { | ||
log.level = ''; | ||
expect(log.$setLevel()).to.be.an.object; | ||
expect(log.level).to.eq('DEBUG'); | ||
logger.$$level = ''; | ||
expect(logger.$setLevel()).to.be.an.object; | ||
expect(logger.$$level).to.deep.eq(new Set('DEBUG')); | ||
}); | ||
it('test called with a bad argument', function() { | ||
log.level = ''; | ||
expect(log.$setLevel('test')).to.be.an.object; | ||
expect(log.level).to.eq('DEBUG'); | ||
logger.$$level = ''; | ||
expect(logger.$setLevel('test')).to.be.an.object; | ||
expect(logger.$$level).to.deep.eq(new Set('DEBUG')); | ||
}); | ||
it('test called with a good argument', function() { | ||
log.level = ''; | ||
expect(log.$setLevel('info')).to.be.an.object; | ||
expect(log.level).to.eq('INFO'); | ||
logger.$$level = ''; | ||
expect(logger.$setLevel('info')).to.be.an.object; | ||
expect(logger.$$level).to.deep.eq(new Set('INFO')); | ||
}); | ||
}); | ||
describe('$setLevels', function() { | ||
let logger; | ||
beforeEach(function() { | ||
logger = new Log(); | ||
}); | ||
it('test called without an argument', function() { | ||
logger.$$level = ''; | ||
expect(logger.$setLevels()).to.be.an.object; | ||
expect(logger.$$level).to.eq(''); | ||
}); | ||
it('test called with a bad argument', function() { | ||
logger.$$level = ''; | ||
expect(logger.$setLevels('debug')).to.be.an.object; | ||
expect(logger.$$level).to.eq(''); | ||
expect(logger.$setLevels([])).to.be.an.object; | ||
expect(logger.$$level).to.eq(''); | ||
}); | ||
it('test called with a good argument', function() { | ||
logger.$$level = ''; | ||
expect(logger.$setLevels([ 'info', 'debug' ])).to.be.an.object; | ||
expect(logger.$$level).to.deep.eq(new Set('INFO', 'DEBUG')); | ||
}); | ||
}); | ||
describe('$setSilent', function() { | ||
let log; | ||
let logger; | ||
beforeEach(function() { | ||
log = new Log(); | ||
logger = new Log(); | ||
}); | ||
it('test called without an argument', function() { | ||
log.silent = ''; | ||
expect(log.$setSilent()).to.be.an.object; | ||
expect(log.silent).to.be.false; | ||
logger.$$silent = ''; | ||
expect(logger.$setSilent()).to.be.an.object; | ||
expect(logger.$$silent).to.be.false; | ||
}); | ||
it('test called with an argument', function() { | ||
log.silent = ''; | ||
expect(log.$setSilent(true)).to.be.an.object; | ||
expect(log.silent).to.be.true; | ||
logger.$$silent = ''; | ||
expect(logger.$setSilent(true)).to.be.an.object; | ||
expect(logger.$$silent).to.be.true; | ||
}); | ||
}); | ||
describe('$$filter', function() { | ||
let logger; | ||
beforeEach(function() { | ||
logger = new Log(); | ||
mock(logger, '$$logger', noop); | ||
}); | ||
it('test $$filter called with no level', function() { | ||
expect(logger.$$filter()).to.be.an.object; | ||
expect(logger.$$logger).to.not.have.been.called; | ||
}); | ||
it('test $$filter called with invalid level', function() { | ||
expect(logger.$$filter('test')).to.be.an.object; | ||
expect(logger.$$logger).to.not.have.been.called; | ||
}); | ||
describe('test $$filter called with valid level', function() { | ||
it('test default levels', function() { | ||
expect(logger.$$filter('debug', 'test')).to.be.an.object; | ||
expect( | ||
logger.$$logger.calls[0].args | ||
).to.deep.eq([ 'debug', 'test' ]); | ||
}); | ||
it('test custom levels', function() { | ||
logger.$setLevel('info'); | ||
expect(logger.$$filter('info', 'test')).to.be.an.object; | ||
expect( | ||
logger.$$logger.calls[0].args | ||
).to.deep.eq([ 'info', 'test' ]); | ||
}); | ||
}); | ||
}); | ||
describe('$$logger', function() { | ||
let logger; | ||
beforeEach(function() { | ||
mock(Object, 'observe', noop); | ||
mock(Date.prototype, 'toString', () => 'test'); | ||
logger = new Log('angie.log', 'test'); | ||
mock(Log, 'debug', noop); | ||
}); | ||
afterEach(() => simple.restore()); | ||
describe('test no specified log level', function() { | ||
beforeEach(function() { | ||
mock(Log, 'warn', noop); | ||
}); | ||
it('test without name', function() { | ||
logger.$$name = null; | ||
expect(logger.$$logger('test')).to.be.an.object; | ||
expect(Log.warn.calls[0].args[0]).to.eq( | ||
'$$logger called explicitly without a valid log level' | ||
); | ||
}); | ||
it('test with name', function() { | ||
expect(logger.$$logger('test')).to.be.an.object; | ||
expect(Log.warn.calls[0].args[0]).to.eq( | ||
`[${chalk.cyan('test')}] $$logger called explicitly ` + | ||
'without a valid log level' | ||
); | ||
}); | ||
}); | ||
it('test with timestamp', function() { | ||
expect(logger.$$logger('debug', 'test')).to.be.an.object; | ||
expect(logger.$$messages.length).to.eq(1); | ||
expect(logger.$$messages[0]).to.eq( | ||
'[test] [DEBUG] [test] : test\r' | ||
); | ||
expect(Log.debug.calls[0].args[0]).to.deep.eq([ 'test' ]); | ||
}); | ||
it('test without timestamp', function() { | ||
logger.$setTimestamp(false); | ||
expect(logger.$$logger('debug', 'test')).to.be.an.object; | ||
expect(logger.$$messages.length).to.eq(1); | ||
expect(logger.$$messages[0]).to.eq( | ||
'[DEBUG] [test] : test\r' | ||
); | ||
expect(Log.debug.calls[0].args[0]).to.deep.eq([ 'test' ]); | ||
}); | ||
it('test silent', function() { | ||
logger.$setSilent(true); | ||
expect(logger.$$logger('debug', 'test')).to.be.an.object; | ||
expect(logger.$$messages.length).to.eq(1); | ||
expect(logger.$$messages[0]).to.eq( | ||
'[test] [DEBUG] [test] : test\r' | ||
); | ||
expect(Log.debug).to.not.have.been.called; | ||
}); | ||
}); | ||
describe('$$resetLevels', function() { | ||
let logger; | ||
beforeEach(function() { | ||
logger = new Log(); | ||
logger.$$initialLevel = 'test'; | ||
mock(logger, '$setLevels', noop); | ||
}); | ||
it('test reset', function() { | ||
logger.$$resetLevels(); | ||
expect(logger.$setLevels.calls[0].args[0]).to.eq('test'); | ||
}); | ||
}); | ||
describe('log methods', function() { | ||
@@ -225,6 +416,2 @@ beforeEach(function() { | ||
afterEach(() => simple.restore()); | ||
it('bold', function() { | ||
Log.bold('test', 'test'); | ||
expect(console.log.calls[0].args[0]).to.eq(bold('test', 'test')); | ||
}); | ||
it('info', function() { | ||
@@ -234,3 +421,3 @@ Log.info('test\n', 'test\n'); | ||
bold.apply(null, [ | ||
chalk.green('[test] INFO :'), | ||
chalk.green('[test] [INFO] :'), | ||
'test ', | ||
@@ -246,3 +433,3 @@ 'test ', | ||
bold.apply(null, [ | ||
'[test] DEBUG :', | ||
'[test] [DEBUG] :', | ||
'test ', | ||
@@ -258,3 +445,3 @@ 'test ', | ||
bold.apply(null, [ | ||
chalk.yellow('[test] WARN :'), | ||
chalk.yellow('[test] [WARN] :'), | ||
'test ', | ||
@@ -270,3 +457,3 @@ 'test ', | ||
bold.apply(null, [ | ||
chalk.red('[test] ERROR :'), | ||
chalk.red('[test] [ERROR] :'), | ||
'test ', | ||
@@ -282,3 +469,3 @@ 'test ', | ||
bold.apply(null, [ | ||
chalk.red('[test] ERROR :'), | ||
chalk.red('[test] [ERROR] :'), | ||
'stack', | ||
@@ -285,0 +472,0 @@ 'test ', |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
46625
12
931
72
0
7
16
+ Addedbabel-core@^5.8.23
+ Addedgulp@3.9.0
+ Addedgulp-babel@^5.1.0
+ Addedgulp-cli@0.2.0
+ Addedyargs@^3.21.0
+ Addedansi-gray@0.1.1(transitive)
+ Addedansi-regex@2.1.1(transitive)
+ Addedansi-wrap@0.1.0(transitive)
+ Addedarchy@1.0.0(transitive)
+ Addedarray-differ@1.0.0(transitive)
+ Addedarray-each@1.0.1(transitive)
+ Addedarray-slice@1.1.0(transitive)
+ Addedarray-uniq@1.0.3(transitive)
+ Addedbeeper@1.1.1(transitive)
+ Addedcamelcase@2.1.1(transitive)
+ Addedcliui@3.2.0(transitive)
+ Addedclone@0.2.01.0.4(transitive)
+ Addedclone-stats@0.0.1(transitive)
+ Addedcode-point-at@1.1.0(transitive)
+ Addedcolor-support@1.1.3(transitive)
+ Addeddateformat@2.2.0(transitive)
+ Addeddefaults@1.0.4(transitive)
+ Addeddeprecated@0.0.1(transitive)
+ Addeddetect-file@1.0.0(transitive)
+ Addedduplexer2@0.0.2(transitive)
+ Addedend-of-stream@0.1.5(transitive)
+ Addedexpand-tilde@2.0.2(transitive)
+ Addedextend@3.0.2(transitive)
+ Addedfancy-log@1.3.3(transitive)
+ Addedfind-index@0.1.1(transitive)
+ Addedfindup-sync@2.0.0(transitive)
+ Addedfined@1.2.0(transitive)
+ Addedfirst-chunk-stream@1.0.0(transitive)
+ Addedflagged-respawn@1.0.1(transitive)
+ Addedfor-own@1.0.0(transitive)
+ Addedgaze@0.5.2(transitive)
+ Addedglob@3.1.214.5.3(transitive)
+ Addedglob-stream@3.1.18(transitive)
+ Addedglob-watcher@0.0.6(transitive)
+ Addedglob2base@0.0.12(transitive)
+ Addedglobal-modules@1.0.0(transitive)
+ Addedglobal-prefix@1.0.2(transitive)
+ Addedglobule@0.1.0(transitive)
+ Addedglogg@1.0.2(transitive)
+ Addedgraceful-fs@1.2.33.0.12(transitive)
+ Addedgulp@3.9.0(transitive)
+ Addedgulp-babel@5.3.0(transitive)
+ Addedgulp-cli@0.2.0(transitive)
+ Addedgulp-util@3.0.8(transitive)
+ Addedgulplog@1.0.0(transitive)
+ Addedhas-gulplog@0.1.0(transitive)
+ Addedhomedir-polyfill@1.0.3(transitive)
+ Addedinherits@1.0.2(transitive)
+ Addedini@1.3.8(transitive)
+ Addedinterpret@0.4.30.6.6(transitive)
+ Addedis-absolute@1.0.0(transitive)
+ Addedis-extglob@2.1.1(transitive)
+ Addedis-fullwidth-code-point@1.0.0(transitive)
+ Addedis-glob@3.1.0(transitive)
+ Addedis-relative@1.0.0(transitive)
+ Addedis-unc-path@1.0.0(transitive)
+ Addedis-utf8@0.2.1(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedisexe@2.0.0(transitive)
+ Addedliftoff@2.5.0(transitive)
+ Addedlodash@1.0.2(transitive)
+ Addedlodash._basecopy@3.0.1(transitive)
+ Addedlodash._basetostring@3.0.1(transitive)
+ Addedlodash._basevalues@3.0.0(transitive)
+ Addedlodash._getnative@3.9.1(transitive)
+ Addedlodash._isiterateecall@3.0.9(transitive)
+ Addedlodash._reescape@3.0.0(transitive)
+ Addedlodash._reevaluate@3.0.0(transitive)
+ Addedlodash._reinterpolate@3.0.0(transitive)
+ Addedlodash._root@3.0.1(transitive)
+ Addedlodash.escape@3.2.0(transitive)
+ Addedlodash.isarguments@3.1.0(transitive)
+ Addedlodash.isarray@3.0.4(transitive)
+ Addedlodash.keys@3.1.2(transitive)
+ Addedlodash.restparam@3.6.1(transitive)
+ Addedlodash.template@3.6.2(transitive)
+ Addedlodash.templatesettings@3.1.1(transitive)
+ Addedlru-cache@2.7.3(transitive)
+ Addedmake-iterator@1.0.1(transitive)
+ Addedminimatch@0.2.14(transitive)
+ Addedmultipipe@0.1.2(transitive)
+ Addednatives@1.1.6(transitive)
+ Addednumber-is-nan@1.0.1(transitive)
+ Addedobject-assign@3.0.0(transitive)
+ Addedobject.defaults@1.1.0(transitive)
+ Addedobject.map@1.0.1(transitive)
+ Addedonce@1.3.3(transitive)
+ Addedorchestrator@0.3.8(transitive)
+ Addedordered-read-streams@0.1.0(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedparse-filepath@1.0.2(transitive)
+ Addedparse-node-version@1.0.1(transitive)
+ Addedparse-passwd@1.0.0(transitive)
+ Addedpath-root@0.1.1(transitive)
+ Addedpath-root-regex@0.1.2(transitive)
+ Addedpretty-hrtime@0.2.21.0.3(transitive)
+ Addedreadable-stream@1.0.341.1.14(transitive)
+ Addedrechoir@0.6.2(transitive)
+ Addedreplace-ext@0.0.1(transitive)
+ Addedresolve-dir@1.0.1(transitive)
+ Addedsemver@4.3.6(transitive)
+ Addedsequencify@0.0.7(transitive)
+ Addedsigmund@1.0.1(transitive)
+ Addedsparkles@1.0.1(transitive)
+ Addedstream-consume@0.1.1(transitive)
+ Addedstring-width@1.0.2(transitive)
+ Addedstring_decoder@0.10.31(transitive)
+ Addedstrip-ansi@3.0.1(transitive)
+ Addedstrip-bom@1.0.0(transitive)
+ Addedthrough2@0.6.52.0.5(transitive)
+ Addedtildify@1.2.0(transitive)
+ Addedtime-stamp@1.1.0(transitive)
+ Addedunc-path-regex@0.1.2(transitive)
+ Addedunique-stream@1.0.0(transitive)
+ Addedv8flags@2.1.1(transitive)
+ Addedvinyl@0.4.60.5.3(transitive)
+ Addedvinyl-fs@0.3.14(transitive)
+ Addedvinyl-sourcemaps-apply@0.2.1(transitive)
+ Addedwhich@1.3.1(transitive)
+ Addedwrap-ansi@2.1.0(transitive)
+ Addedxtend@4.0.2(transitive)
+ Addedyargs@3.32.0(transitive)