Comparing version 0.0.4 to 0.1.0
75
cli.js
#!/usr/bin/env node | ||
'use strict'; | ||
var argv = require('minimist')(process.argv.slice(2)); | ||
var pkg = require('./package.json'); | ||
var ava = require('./'); | ||
var input = argv._; | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var globby = require('globby'); | ||
var meow = require('meow'); | ||
var updateNotifier = require('update-notifier'); | ||
function help() { | ||
console.log([ | ||
pkg.description, | ||
'', | ||
var cli = meow({ | ||
help: [ | ||
'Usage', | ||
' $ ava <file>', | ||
' ava <file|folder|glob> [...]', | ||
'', | ||
'Example', | ||
' $ ava test.js' | ||
].join('\n')); | ||
} | ||
'Examples', | ||
' ava', | ||
' ava test.js test2.js', | ||
' ava test-*.js', | ||
'', | ||
'Default patterns when no arguments:', | ||
'test.js test-*.js test/**' | ||
] | ||
}, { | ||
string: ['_'] | ||
}); | ||
if (input.length === 0 || argv.help) { | ||
help(); | ||
return; | ||
function run(file) { | ||
fs.stat(file, function (err, stats) { | ||
if (err) { | ||
console.error(err.message); | ||
process.exit(1); | ||
} | ||
if (stats.isDirectory()) { | ||
init(path.join(file, '*.js')); | ||
return; | ||
} | ||
require(file); | ||
}); | ||
} | ||
if (argv.version) { | ||
console.log(pkg.version); | ||
return; | ||
function init(files) { | ||
if (files.length === 0) { | ||
files = [ | ||
'test.js', | ||
'test-*.js', | ||
'test/**' | ||
]; | ||
} | ||
globby(files, function (err, files) { | ||
if (err) { | ||
console.error(err.message); | ||
process.exit(1); | ||
} | ||
files.forEach(function (file) { | ||
run(path.resolve(process.cwd(), file)); | ||
}); | ||
}); | ||
} | ||
console.log('not yet implemented'); | ||
updateNotifier({pkg: cli.pkg}).notify(); | ||
init(cli.input); |
75
index.js
'use strict'; | ||
var chalk = require('chalk'); | ||
var logSymbols = require('log-symbols'); | ||
var figures = require('figures'); | ||
var Squeak = require('squeak'); | ||
var plur = require('plur'); | ||
var Runner = require('./lib/runner'); | ||
var log = new Squeak({separator: ' '}); | ||
var runner = new Runner(); | ||
setImmediate(function () { | ||
runner.on('test', function (err, title) { | ||
if (err) { | ||
console.log(' ', logSymbols.error, title, ' ', chalk.red(err.message)); | ||
log.type('success', { | ||
color: 'green', | ||
prefix: figures.tick | ||
}); | ||
log.type('error', { | ||
color: 'red', | ||
prefix: figures.cross | ||
}); | ||
function test(err, title) { | ||
if (err) { | ||
log.error(title, chalk.red(err.message)); | ||
return; | ||
} | ||
log.success(title); | ||
} | ||
function stack(results) { | ||
var i = 0; | ||
results.forEach(function (result) { | ||
if (!result.error) { | ||
return; | ||
} | ||
console.log(' ', logSymbols.success, title); | ||
i++; | ||
log.writelpad(chalk.red(i + '.', result.title)); | ||
log.writelpad(chalk.red(result.error.stack)); | ||
log.write(); | ||
}); | ||
} | ||
runner.run(function (stats, results) { | ||
if (stats.failCount === 0) { | ||
console.log(chalk.green('\n ', logSymbols.success, stats.passCount, (stats.passCount === 1 ? 'test' : 'tests'), 'passed\n')); | ||
} else { | ||
console.log(chalk.red('\n ', logSymbols.error, stats.failCount, (stats.failCount === 1 ? 'test' : 'tests'), 'failed\n')); | ||
// TODO: show detailed fails when at least one test failed | ||
} | ||
function exit(stats, results) { | ||
if (stats.testCount > 0) { | ||
log.write(); | ||
} | ||
process.exit(stats.failCount > 0 ? 1 : 0); | ||
}); | ||
if (stats.failCount === 0) { | ||
log.writelpad(chalk.green(stats.passCount, plur('test', stats.passCount), 'passed')); | ||
} else { | ||
log.writelpad(chalk.red(stats.failCount, plur('test', stats.failCount), 'failed')); | ||
} | ||
log.write(); | ||
if (stats.failCount > 0) { | ||
stack(results); | ||
} | ||
process.exit(stats.failCount > 0 ? 1 : 0); | ||
} | ||
setImmediate(function () { | ||
runner.on('test', test); | ||
runner.run(exit); | ||
}); | ||
module.exports = runner.addTest.bind(runner); | ||
// TODO: expose it when more stable | ||
//module.exports.Runner = Runner; | ||
module.exports.serial = runner.addSerialTest.bind(runner); |
'use strict'; | ||
var inherits = require('util').inherits; | ||
var util = require('util'); | ||
var EventEmitter = require('events').EventEmitter; | ||
var eachAsync = require('each-async'); | ||
var each = require('each-async'); | ||
var eachSerial = require('async-each-series'); | ||
var Test = require('./test'); | ||
inherits(Runner, EventEmitter); | ||
function Runner(opts) { | ||
if (!(this instanceof Runner)) { | ||
return new Runner(opts); | ||
} | ||
function Runner(opts) { | ||
this._tests = []; | ||
this._results = []; | ||
this._firstError = null; | ||
this._failCount = 0; | ||
EventEmitter.call(this); | ||
this.results = []; | ||
this.stats = {}; | ||
this.stats.failCount = 0; | ||
this.stats.testCount = 0; | ||
this.tests = {}; | ||
this.tests.concurrent = []; | ||
this.tests.serial = []; | ||
} | ||
util.inherits(Runner, EventEmitter); | ||
module.exports = Runner; | ||
Runner.prototype.addTest = function (title, cb) { | ||
this._tests.push(new Test(title, cb)); | ||
this.stats.testCount++; | ||
this.tests.concurrent.push(new Test(title, cb)); | ||
}; | ||
Runner.prototype.run = function (cb) { | ||
var self = this; | ||
Runner.prototype.addSerialTest = function (title, cb) { | ||
this.stats.testCount++; | ||
this.tests.serial.push(new Test(title, cb)); | ||
}; | ||
eachAsync(this._tests, function (test, i, next) { | ||
Runner.prototype.concurrent = function (cb) { | ||
each(this.tests.concurrent, function (test, i, next) { | ||
test.run(function (err) { | ||
if (err) { | ||
if (!self._firstError) { | ||
self._firstError = err; | ||
} | ||
this.stats.failCount++; | ||
} | ||
self._failCount++; | ||
this.results.push({ | ||
title: test.title, | ||
error: err | ||
}); | ||
this.emit('test', err, test.title); | ||
next(); | ||
}.bind(this)); | ||
}.bind(this), cb); | ||
}; | ||
Runner.prototype.serial = function (cb) { | ||
eachSerial(this.tests.serial, function (test, next) { | ||
test.run(function (err) { | ||
if (err) { | ||
this.stats.failCount++; | ||
} | ||
self._results.push({ | ||
this.results.push({ | ||
title: test.title, | ||
@@ -38,18 +67,33 @@ error: err | ||
self.emit('test', err, test.title); | ||
this.emit('test', err, test.title); | ||
next(); | ||
}); | ||
}, function () { | ||
var testCount = self._tests.length; | ||
var failCount = self._failCount; | ||
var passCount = testCount - failCount; | ||
}.bind(this)); | ||
}.bind(this), cb); | ||
}; | ||
cb({ | ||
testCount: testCount, | ||
failCount: failCount, | ||
passCount: passCount | ||
}, self._results); | ||
}); | ||
Runner.prototype.run = function (cb) { | ||
var concurrent = this.tests.concurrent; | ||
var serial = this.tests.serial; | ||
if (serial.length > 0 && concurrent.length === 0) { | ||
this.serial(this.end.bind(this, cb)); | ||
return; | ||
} | ||
if (serial.length === 0 && concurrent.length > 0) { | ||
this.concurrent(this.end.bind(this, cb)); | ||
return; | ||
} | ||
if (serial.length > 0 && concurrent.length > 0) { | ||
this.serial(this.concurrent.bind(this, this.end.bind(this, cb))); | ||
return; | ||
} | ||
this.end(cb); | ||
}; | ||
module.exports = Runner; | ||
Runner.prototype.end = function (cb) { | ||
this.stats.passCount = this.stats.testCount - this.stats.failCount; | ||
cb(this.stats, this.results); | ||
}; |
131
lib/test.js
'use strict'; | ||
var util = require('util'); | ||
var assert = require('assert'); | ||
var inherits = require('util').inherits; | ||
var EventEmitter = require('events').EventEmitter; | ||
var fnName = require('fn-name'); | ||
var claim = require('claim'); | ||
inherits(Test, EventEmitter); | ||
function Test(title, fn) { | ||
if (!(this instanceof Test)) { | ||
return new Test(title, fn); | ||
} | ||
function Test(title, fn) { | ||
if (typeof title !== 'string') { | ||
@@ -14,43 +18,34 @@ fn = title; | ||
this.title = title || fn.name || '[anonymous]'; | ||
this._fn = fn; | ||
this._plan = null; | ||
this._skip = false; | ||
this._assertCount = 0; | ||
this._assertError = null; | ||
this._endCalled = false; | ||
this._ended = false; | ||
EventEmitter.call(this); | ||
this.title = title || fnName(fn) || '[anonymous]'; | ||
this.fn = fn; | ||
this.assertCount = 0; | ||
this.planCount = null; | ||
} | ||
Test.prototype.end = function () { | ||
if (this._endCalled) { | ||
// throw? | ||
console.error('.end() called more than once'); | ||
} | ||
util.inherits(Test, EventEmitter); | ||
module.exports = Test; | ||
this._endCalled = true; | ||
this._end(); | ||
}; | ||
Test.prototype._assert = function () { | ||
this.assertCount++; | ||
Test.prototype._end = function () { | ||
if (!this._ended) { | ||
this.emit('end'); | ||
if (this.assertCount === this.planCount) { | ||
setImmediate(this.exit.bind(this)); | ||
} | ||
this._ended = true; | ||
}; | ||
Test.prototype.assert = function () { | ||
try { | ||
assert.apply(null, arguments); | ||
} catch (err) { | ||
this._assertError = err; | ||
this._end(); | ||
return; | ||
} | ||
// TODO: find a better way to count assertions | ||
// decorate the `claim` methods with our assert counter | ||
Object.keys(claim).forEach(function (el) { | ||
Test.prototype[el] = function () { | ||
this._assert(); | ||
if (this._plan === ++this._assertCount) { | ||
this._end(); | ||
} | ||
}; | ||
try { | ||
claim[el].apply(claim, arguments); | ||
} catch (err) { | ||
this.assertError = err; | ||
} | ||
}; | ||
}); | ||
@@ -62,31 +57,65 @@ Test.prototype.plan = function (count) { | ||
this._plan = count; | ||
this.planCount = count; | ||
}; | ||
Test.prototype.skip = function () { | ||
this._skip = true; | ||
this.skipTest = true; | ||
}; | ||
Test.prototype.run = function (cb) { | ||
if (!this._fn || this._skip) { | ||
return; | ||
this.cb = cb; | ||
if (!this.fn || this.skipTest) { | ||
this.exit(); | ||
} | ||
this.on('end', function () { | ||
cb(this._assertError); | ||
}); | ||
try { | ||
var ret = this.fn(this); | ||
try { | ||
this._fn(this); | ||
if (ret && typeof ret.then === 'function') { | ||
ret.then(this.exit.bind(this)).catch(function (err) { | ||
this.assertError = new assert.AssertionError({ | ||
actual: err, | ||
message: 'Promise rejected → ' + err, | ||
operator: 'promise', | ||
stackStartFunction: this | ||
}); | ||
this.exit(); | ||
}.bind(this)); | ||
} | ||
} catch (err) { | ||
this._assertError = err; | ||
this._end(); | ||
this.assertError = err; | ||
this.exit(); | ||
} | ||
}; | ||
// end on the next event loop if there weren't any planned asserts | ||
if (this._plan === null) { | ||
setImmediate(this._end.bind(this)); | ||
Test.prototype.end = function () { | ||
if (this.endCalled) { | ||
throw new Error('.end() called more than once'); | ||
} | ||
this.endCalled = true; | ||
this.exit(); | ||
}; | ||
module.exports = Test; | ||
Test.prototype.exit = function () { | ||
if (this.planCount !== null && this.planCount !== this.assertCount) { | ||
this.assertError = new assert.AssertionError({ | ||
actual: this.assertCount, | ||
expected: this.planCount, | ||
message: 'Assertion count does not match planned', | ||
operator: 'plan', | ||
// TODO: find out why it doesn't show any stack | ||
stackStartFunction: this.fn | ||
}); | ||
} | ||
if (!this.ended) { | ||
this.ended = true; | ||
setImmediate(function () { | ||
this.cb(this.assertError); | ||
}.bind(this)); | ||
} | ||
}; |
{ | ||
"name": "ava", | ||
"version": "0.0.4", | ||
"description": "WIP - Simple test runner", | ||
"version": "0.1.0", | ||
"description": "Simple concurrent test runner", | ||
"license": "MIT", | ||
"repository": "sindresorhus/ava", | ||
"bin": { | ||
"ava": "cli.js" | ||
}, | ||
"author": { | ||
"name": "Sindre Sorhus", | ||
"email": "sindresorhus@gmail.com", | ||
"url": "http://sindresorhus.com" | ||
}, | ||
"homepage": "http://ava.li", | ||
"maintainers": [ | ||
{ | ||
"name": "Sindre Sorhus", | ||
"email": "sindresorhus@gmail.com", | ||
"url": "sindresorhus.com" | ||
}, | ||
{ | ||
"name": "Kevin Mårtensson", | ||
"email": "kevinmartensson@gmail.com", | ||
"url": "github.com/kevva" | ||
} | ||
], | ||
"bin": "cli.js", | ||
"engines": { | ||
@@ -19,3 +25,3 @@ "node": ">=0.10.0" | ||
"scripts": { | ||
"test": "node test/test.js" | ||
"test": "xo && node test/test.js | tap-dot" | ||
}, | ||
@@ -28,14 +34,35 @@ "files": [ | ||
"keywords": [ | ||
"cli-app", | ||
"cli", | ||
"bin" | ||
"ava", | ||
"test", | ||
"runner", | ||
"concurrent", | ||
"parallel", | ||
"fast", | ||
"tape", | ||
"tap", | ||
"mocha", | ||
"qunit", | ||
"jasmine" | ||
], | ||
"dependencies": { | ||
"chalk": "^0.5.1", | ||
"async-each-series": "^1.0.0", | ||
"chalk": "^1.0.0", | ||
"claim": "^1.3.0", | ||
"each-async": "^1.0.0", | ||
"log-symbols": "^1.0.0", | ||
"minimist": "^1.1.0" | ||
"figures": "^1.3.5", | ||
"fn-name": "^2.0.0", | ||
"globby": "^2.0.0", | ||
"meow": "^3.3.0", | ||
"plur": "^2.0.0", | ||
"squeak": "^1.2.0", | ||
"update-notifier": "^0.5.0" | ||
}, | ||
"devDependencies": { | ||
"ava": "0.0.3" | ||
"pinkie-promise": "^1.0.0", | ||
"tap-dot": "^1.0.0", | ||
"tape": "^4.0.0", | ||
"xo": "*" | ||
} | ||
} |
203
readme.md
@@ -1,11 +0,15 @@ | ||
# ava [![Build Status](https://travis-ci.org/sindresorhus/ava.svg?branch=master)](https://travis-ci.org/sindresorhus/ava) | ||
# ![AVA](media/header.png) | ||
> WIP - Simple test runner | ||
> Simple concurrent test runner | ||
[![Build Status](https://travis-ci.org/sindresorhus/ava.svg?branch=master)](https://travis-ci.org/sindresorhus/ava) | ||
Even though JavaScript is single-threaded, IO in Node.js can happen in parallel due to its async nature. AVA takes advantage of this and runs your tests concurrently, which is especially beneficial for IO heavy tests. [Switching](https://github.com/sindresorhus/pageres/commit/663be15acb3dd2eb0f71b1956ef28c2cd3fdeed0) from Mocha to AVA in Pageres brought the test time down from 31 sec to 11 sec. Having tests run concurrently forces you to write atomic tests, meaning tests that don't depend on global state or the state of other tests, which is a great thing! | ||
## Install | ||
```sh | ||
$ npm install --save-dep ava | ||
``` | ||
$ npm install --save-dev ava | ||
``` | ||
@@ -15,3 +19,3 @@ | ||
##### Add it to `package.json` | ||
##### Add it to package.json | ||
@@ -26,2 +30,3 @@ ```json | ||
##### Create your test file | ||
@@ -32,11 +37,22 @@ | ||
test('test something', function (t) { | ||
t.plan(1); | ||
t.assert(true); | ||
test('foo', function (t) { | ||
t.pass(); | ||
t.end(); | ||
}); | ||
test('bar', function (t) { | ||
t.plan(2) | ||
setTimeout(function () { | ||
t.is('bar', 'bar'); | ||
t.same(['a', 'b'], ['a', 'b']); | ||
}, 100); | ||
}); | ||
``` | ||
<img src="screenshot.png" width="150" align="right"> | ||
##### Run it | ||
```sh | ||
``` | ||
$ npm test | ||
@@ -46,4 +62,171 @@ ``` | ||
## CLI | ||
``` | ||
$ ava --help | ||
Usage | ||
ava <file|folder|glob> [...] | ||
Examples | ||
ava | ||
ava test.js test2.js | ||
ava test-*.js | ||
Default patterns when no arguments: | ||
test.js test-*.js test/** | ||
``` | ||
## Documentation | ||
Test files are just normal Node.js scripts and can be run with `$ node test.js`. However, using the CLI is preferred for simplicity and future [parallelism support](https://github.com/sindresorhus/ava/issues/1). | ||
Tests are run async and require you to either set planned assertions `t.plan(1)`, explicitly end the test when done `t.end()`, or return a promise. | ||
You have to define all tests synchronously, meaning you can't define a test in the next tick, e.g. inside a `setTimeout`. | ||
### Test anatomy | ||
To create a test, you just call the `test` function you require'd from AVA and pass in an optional test name and a callback function containing the test execution. The passed callback function is given the context as the first argument where you can call the different AVA methods and assertions. | ||
```js | ||
test('name', function (t) { | ||
t.pass(); | ||
t.end(); | ||
}); | ||
``` | ||
### Optional test name | ||
Naming a test is optional, but you're recommended to use one if you have more than one test. | ||
```js | ||
test(function (t) { | ||
t.end(); | ||
}); | ||
``` | ||
You can also choose to use a named function instead: | ||
```js | ||
test(function name(t) { | ||
t.end(); | ||
}); | ||
``` | ||
### Planned assertions | ||
Planned assertions are useful for being able to assert that all async actions happened and catch bugs where too many assertions happen. It also comes with the benefit of not having to manually end the test. | ||
This will result in a passed test: | ||
```js | ||
test(function (t) { | ||
t.plan(1); | ||
setTimeout(function () { | ||
t.pass(); | ||
}, 100); | ||
}); | ||
``` | ||
And this will result in an error because the code called more assertions than planned: | ||
```js | ||
test(function (t) { | ||
t.plan(1); | ||
t.pass(); | ||
setTimeout(function () { | ||
t.pass(); | ||
}, 100); | ||
}); | ||
``` | ||
### Promise support | ||
If you return a promise in the test you don't need to explicitly end the test as it will end when the promise resolves. | ||
```js | ||
test(function (t) { | ||
return somePromise().then(function (result) { | ||
t.is(result, 'unicorn'); | ||
}); | ||
}); | ||
``` | ||
### Serial test execution | ||
While concurrency is awesome, there are some things that can't be done concurrently. In these rare cases, you can call `test.serial`, which will force those tests to run serially before the concurrent ones. | ||
```js | ||
test.serial(function (t) { | ||
t.end(); | ||
}); | ||
``` | ||
## API | ||
### test([name], body) | ||
### test.serial([name], body) | ||
#### name | ||
Type: `string` | ||
Test name. | ||
#### body(context) | ||
Type: `function` | ||
Should contain the actual test. | ||
##### context | ||
Passed into the test function and contains the different AVA methods and assertions. | ||
See the [`claim` docs](https://github.com/kevva/claim#api) for supported assertions. | ||
###### plan(count) | ||
Plan how many assertion there are in the test. The test will fail if the actual assertion count doesn't match planned assertions. When planned assertions are used you don't need to explicitly end the test. | ||
Be aware that this doesn't work with custom assert modules. You must then call `.end()` explicitly. | ||
###### end() | ||
End the test. Use this when `plan()` is not used. | ||
## Tips | ||
### Temp files | ||
Running tests concurrently comes with some challenges, doing IO is one. Usually, serial tests just create temp directories in the current test directory and cleans it up at the end. This won't work when you run tests concurrently as tests will conflict with each other. The correct way to do it is to use a new temp directory for each test. The [`tempfile`](https://github.com/sindresorhus/tempfile) and [`temp-write`](https://github.com/sindresorhus/temp-write) modules can be helpful. | ||
## FAQ | ||
### Why not `mocha`, `tape`, `node-tap`? | ||
Mocha requires you to use implicit globals like `describe` and `it`, too unopinionated, bloated, synchronous by default, serial test execution, and slow. Tape and node-tap are pretty good. AVA is highly inspired by their syntax. However, they both execute tests serially and they've made [TAP](https://testanything.org) a first-class citizen which has IMHO made their codebases a bit convoluted and coupled. TAP output is hard to read so you always end up using an external tap reporter. AVA is highly opinionated and concurrent. It comes with a default simple reporter and will in the future support TAP through a reporter. | ||
## License | ||
MIT © [Sindre Sorhus](http://sindresorhus.com) | ||
MIT © [Sindre Sorhus](http://sindresorhus.com) & [Kevin Mårtensson](https://github.com/kevva) | ||
<div align="center"> | ||
<br> | ||
<br> | ||
<br> | ||
<img src="https://cdn.rawgit.com/sindresorhus/ava/fe1cea1ca3d2c8518c0cc39ec8be592beab90558/media/logo.svg" width="200" alt="AVA"> | ||
<br> | ||
<br> | ||
</div> |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
15186
7
289
1
229
11
4
2
3
1
+ Addedasync-each-series@^1.0.0
+ Addedclaim@^1.3.0
+ Addedfigures@^1.3.5
+ Addedfn-name@^2.0.0
+ Addedglobby@^2.0.0
+ Addedmeow@^3.3.0
+ Addedplur@^2.0.0
+ Addedsqueak@^1.2.0
+ Addedupdate-notifier@^0.5.0
+ Addedarray-find-index@1.0.2(transitive)
+ Addedarray-union@1.0.2(transitive)
+ Addedarray-uniq@1.0.3(transitive)
+ Addedasync@1.5.2(transitive)
+ Addedasync-each-series@1.1.0(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedcamelcase@2.1.1(transitive)
+ Addedcamelcase-keys@2.1.0(transitive)
+ Addedclaim@1.4.0(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedconfigstore@1.4.0(transitive)
+ Addedconsole-stream@0.1.1(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addedcurrently-unhandled@0.4.1(transitive)
+ Addeddecamelize@1.2.0(transitive)
+ Addeddeep-extend@0.6.0(transitive)
+ Addedduplexify@3.7.1(transitive)
+ Addedend-of-stream@1.4.4(transitive)
+ Addederror-ex@1.3.2(transitive)
+ Addedfigures@1.7.0(transitive)
+ Addedfind-up@1.1.2(transitive)
+ Addedfn-name@2.0.1(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-stdin@4.0.1(transitive)
+ Addedglob@5.0.15(transitive)
+ Addedglobby@2.1.0(transitive)
+ Addedgot@3.3.1(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhosted-git-info@2.8.9(transitive)
+ Addedimurmurhash@0.1.4(transitive)
+ Addedindent-string@2.1.0(transitive)
+ Addedinfinity-agent@2.0.3(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedini@1.3.8(transitive)
+ Addedirregular-plurals@1.4.0(transitive)
+ Addedis-arrayish@0.2.1(transitive)
+ Addedis-core-module@2.15.1(transitive)
+ Addedis-finite@1.1.0(transitive)
+ Addedis-npm@1.0.0(transitive)
+ Addedis-redirect@1.0.0(transitive)
+ Addedis-stream@1.1.0(transitive)
+ Addedis-utf8@0.2.1(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedlatest-version@1.0.1(transitive)
+ Addedload-json-file@1.1.0(transitive)
+ Addedlongest@1.0.1(transitive)
+ Addedloud-rejection@1.6.0(transitive)
+ Addedlowercase-keys@1.0.1(transitive)
+ Addedlpad-align@1.1.2(transitive)
+ Addedmap-obj@1.0.1(transitive)
+ Addedmeow@3.7.0(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addednested-error-stacks@1.0.2(transitive)
+ Addednormalize-package-data@2.5.0(transitive)
+ Addedobject-assign@3.0.04.1.1(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedos-tmpdir@1.0.2(transitive)
+ Addedosenv@0.1.5(transitive)
+ Addedpackage-json@1.2.0(transitive)
+ Addedparse-json@2.2.0(transitive)
+ Addedpath-exists@2.1.0(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedpath-parse@1.0.7(transitive)
+ Addedpath-type@1.1.0(transitive)
+ Addedpify@2.3.0(transitive)
+ Addedpinkie@2.0.4(transitive)
+ Addedpinkie-promise@2.0.1(transitive)
+ Addedplur@2.1.2(transitive)
+ Addedprepend-http@1.0.4(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedrc@1.2.8(transitive)
+ Addedread-all-stream@3.1.0(transitive)
+ Addedread-pkg@1.1.0(transitive)
+ Addedread-pkg-up@1.0.1(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedredent@1.0.0(transitive)
+ Addedregistry-url@3.1.0(transitive)
+ Addedrepeating@1.1.32.0.1(transitive)
+ Addedresolve@1.22.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedsemver-diff@2.1.0(transitive)
+ Addedsignal-exit@3.0.7(transitive)
+ Addedslide@1.1.6(transitive)
+ Addedspdx-correct@3.2.0(transitive)
+ Addedspdx-exceptions@2.5.0(transitive)
+ Addedspdx-expression-parse@3.0.1(transitive)
+ Addedspdx-license-ids@3.0.20(transitive)
+ Addedsqueak@1.3.0(transitive)
+ Addedstream-shift@1.0.3(transitive)
+ Addedstring-length@1.0.1(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedstrip-bom@2.0.0(transitive)
+ Addedstrip-indent@1.0.1(transitive)
+ Addedstrip-json-comments@2.0.1(transitive)
+ Addedsupports-preserve-symlinks-flag@1.0.0(transitive)
+ Addedtimed-out@2.0.0(transitive)
+ Addedtrim-newlines@1.0.0(transitive)
+ Addedupdate-notifier@0.5.0(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addeduuid@2.0.3(transitive)
+ Addedvalidate-npm-package-license@3.0.4(transitive)
+ Addedwrappy@1.0.2(transitive)
+ Addedwrite-file-atomic@1.3.4(transitive)
+ Addedxdg-basedir@2.0.0(transitive)
- Removedlog-symbols@^1.0.0
- Removedminimist@^1.1.0
- Removedansi-regex@0.2.1(transitive)
- Removedansi-styles@1.1.0(transitive)
- Removedchalk@0.5.1(transitive)
- Removedhas-ansi@0.1.0(transitive)
- Removedlog-symbols@1.0.2(transitive)
- Removedstrip-ansi@0.3.0(transitive)
- Removedsupports-color@0.2.0(transitive)
Updatedchalk@^1.0.0