benchmarkify
Advanced tools
Comparing version 1.3.0 to 2.0.0
@@ -7,5 +7,15 @@ { | ||
"configurations": [ | ||
{ | ||
"type": "node", | ||
"request": "launch", | ||
"name": "Example simple", | ||
"program": "${workspaceRoot}\\examples\\index.js", | ||
"args": [ | ||
"simple" | ||
] | ||
}, | ||
{ | ||
"type": "node", | ||
"request": "launch", | ||
"name": "Example multi", | ||
@@ -25,11 +35,4 @@ "program": "${workspaceRoot}\\examples\\index.js", | ||
] | ||
}, | ||
{ | ||
"type": "node", | ||
"request": "attach", | ||
"name": "Attach to Process", | ||
"address": "localhost", | ||
"port": 5858 | ||
} | ||
] | ||
} |
@@ -5,7 +5,2 @@ "use strict"; | ||
let Benchmarkify = require("../"); | ||
Benchmarkify.printHeader("Promise vs BlueBird vs Native"); | ||
let bench1 = new Benchmarkify({ async: true, name: "Promise"}); | ||
function add(a, b) { | ||
@@ -15,34 +10,50 @@ return a + b; | ||
bench1.add("No promise", () => { | ||
return add(5, 8); | ||
}, false); | ||
let Benchmarkify = require("../"); | ||
let benchmark = new Benchmarkify("ES6 Promise vs BlueBird").printHeader(); | ||
bench1.add("ES6 Promise.resolve", () => { | ||
let bench1 = benchmark.createSuite({ name: "Without promise", time: 5000 }); | ||
bench1.add("Sync", () => { | ||
add(5, 8); | ||
}); | ||
bench1.add("Callback", done => { | ||
add(5, 8); | ||
done(); | ||
}); | ||
let bench2 = benchmark.createSuite({ name: "ES6", time: 5000 }); | ||
bench2.add("ES6 Promise.resolve", done => { | ||
return Promise.resolve().then(() => { | ||
return add(5, 8); | ||
add(5, 8); | ||
done(); | ||
}); | ||
}); | ||
bench1.add("ES6 new Promise", () => { | ||
bench2.add("ES6 new Promise", done => { | ||
return new Promise(resolve => { | ||
resolve(add(5, 8)); | ||
done(); | ||
}); | ||
}); | ||
let bench2 = new Benchmarkify({ async: true, name: "BlueBird"}); | ||
let bench3 = benchmark.createSuite({ name: "Bluebird", time: 5000 }) | ||
bench2.add("Bluebird Promise.resolve", () => { | ||
bench3.add("Bluebird Promise.resolve", done => { | ||
return PromiseBB.resolve().then(() => { | ||
return add(5, 8); | ||
add(5, 8); | ||
done(); | ||
}); | ||
}); | ||
bench2.add("Bluebird new Promise", () => { | ||
bench3.add("Bluebird new Promise", done => { | ||
return new PromiseBB(resolve => { | ||
resolve(add(5, 8)); | ||
done(); | ||
}); | ||
}); | ||
Benchmarkify.run([bench1, bench2]).then(res => { | ||
console.log(res); | ||
}); | ||
benchmark.run([bench1, bench2, bench3]).then(res => { | ||
//console.log(JSON.stringify(res, null, 2)); | ||
}); |
"use strict"; | ||
let Benchmarkify = require("../"); | ||
Benchmarkify.printHeader("Multi example"); | ||
let benchmark = new Benchmarkify("Multi example", { spinner: false }).printHeader(); | ||
let bench1 = new Benchmarkify({ async: false, name: "Date performance", resultFile: "./bench-results/multi.json"}); | ||
let bench1 = benchmark.createSuite({ name: "Date performance", time: 1000 }); | ||
@@ -16,2 +16,3 @@ const cycle = 10 * 1000; | ||
} | ||
//throw new Error("Csak úgy!"); | ||
return time; | ||
@@ -29,3 +30,3 @@ }); | ||
let bench2 = new Benchmarkify({ async: false, name: "Increment integer", resultFile: "./bench-results/multi.json"}); | ||
let bench2 = benchmark.createSuite({ name: "Increment integer", time: 1000 }); | ||
@@ -39,3 +40,3 @@ const ITERATION = 1000; | ||
let i2 = 0; | ||
bench2.add("Increment with +=", () => { | ||
bench2.ref("Increment with +=", () => { | ||
i2 += 1; | ||
@@ -49,5 +50,4 @@ }); | ||
Benchmarkify.run([bench1, bench2]) | ||
.then(res => { | ||
console.log(res); | ||
benchmark.run([bench1, bench2]).then(res => { | ||
console.log(JSON.stringify(res, null, 2)); | ||
}); |
"use strict"; | ||
let Benchmarkify = require("../"); | ||
Benchmarkify.printHeader("Simple example"); | ||
let benchmark = new Benchmarkify("Simple example").printHeader(); | ||
let bench = new Benchmarkify({ async: false, name: "String concatenate", resultFile: "./bench-results/simple.json"}); | ||
const ITERATION = 1000; | ||
const ITERATION = 1000; | ||
bench.add("Concat with '+'", () => { | ||
benchmark.createSuite({ | ||
name: "String concatenate", | ||
time: 1000 | ||
}).add("Concat with '+'", () => { | ||
let s = ""; | ||
@@ -14,5 +16,4 @@ for(let i = 0; i < ITERATION; i++) | ||
return s; | ||
}); | ||
bench.add("Concat with array & join", () => { | ||
}).add("Concat with array & join", () => { | ||
let s = []; | ||
@@ -22,6 +23,5 @@ for(let i = 0; i < ITERATION; i++) | ||
return s.join(); | ||
}); | ||
bench.run().then(res => { | ||
console.log(res); | ||
}).run().then(res => { | ||
console.log(JSON.stringify(res, null, 2)); | ||
}); |
682
index.js
const _ = require("lodash"); | ||
const Promise = require("bluebird"); | ||
const chalk = require("chalk"); | ||
const Benchmark = require("benchmark"); | ||
const humanize = require('tiny-human-time'); | ||
const ora = require('ora'); | ||
const spinner = ora({ | ||
text: 'Running benchmark...', | ||
spinner: { | ||
interval: 400, | ||
"frames": [ | ||
". ", | ||
".. ", | ||
"...", | ||
" ..", | ||
" .", | ||
" " | ||
] | ||
} | ||
}); | ||
class Benchmarkify { | ||
constructor(opts) { | ||
this.opts = _.defaultsDeep(opts, { | ||
async: false, | ||
name: "" | ||
/** | ||
* | ||
* | ||
* @param {any} value | ||
* @param {number} [decimals=0] | ||
* @returns | ||
*/ | ||
function formatNumber(value, decimals = 0, sign = false) { | ||
let res = Number(value.toFixed(decimals)).toLocaleString(); | ||
if (sign && value > 0.0) | ||
res = "+" + res; | ||
return res; | ||
} | ||
/** | ||
* | ||
* | ||
* @class TestCase | ||
*/ | ||
class TestCase { | ||
/** | ||
* Creates an instance of TestCase. | ||
* @param {any} suite | ||
* @param {any} name | ||
* @param {any} fn | ||
* @param {any} opts | ||
* | ||
* @memberOf TestCase | ||
*/ | ||
constructor(suite, name, fn, opts) { | ||
this.suite = suite; | ||
this.name = name; | ||
this.fn = fn; | ||
this.async = fn.length > 0; | ||
this.opts = opts || {}; | ||
this.skip = false; | ||
this.done = false; | ||
this.running = false; | ||
this.time = this.opts.time || this.suite.time || 5000; | ||
this.cycles = this.opts.cycles || this.suite.cycles || 1000; | ||
this.minSamples = this.opts.minSamples || this.suite.minSamples || 5; | ||
this.timer = null; | ||
this.startTime = null; | ||
this.startHrTime = null; | ||
this.stat = { | ||
duration: null, | ||
cycle: 0, | ||
count: 0, | ||
avg: null, | ||
rps: null | ||
} | ||
} | ||
/** | ||
* | ||
* | ||
* @returns | ||
* | ||
* @memberOf TestCase | ||
*/ | ||
run() { | ||
const self = this; | ||
return new Promise((resolve, reject) => { | ||
// Start test | ||
self.start(); | ||
// Run | ||
if (self.async) { | ||
self.cyclingAsyncCb(resolve, reject); | ||
} else { | ||
self.cycling(resolve); | ||
} | ||
}); | ||
this.suite = new Benchmark.Suite; | ||
this.logger = this.opts.logger || console; | ||
this.async = this.opts.async; | ||
} | ||
add(name, fn, async = this.async) { | ||
let self = this; | ||
let onStart = function() { | ||
if (self.opts.spinner !== false) { | ||
spinner.text = `Running '${name}'...`; | ||
spinner.start(); | ||
/** | ||
* | ||
* | ||
* | ||
* @memberOf TestCase | ||
*/ | ||
start() { | ||
this.running = true; | ||
this.stat.count = 0; | ||
this.startTime = Date.now(); | ||
this.startHrTime = process.hrtime(); | ||
} | ||
/** | ||
* | ||
* | ||
* | ||
* @memberOf TestCase | ||
*/ | ||
finish() { | ||
const diff = process.hrtime(this.startHrTime); | ||
const count = this.stat.count; | ||
const duration = diff[0] + diff[1] / 1e9; | ||
_.assign(this.stat, { | ||
duration, | ||
avg: duration / count, | ||
rps: count / duration | ||
}); | ||
this.done = true; | ||
this.running = false; | ||
} | ||
/** | ||
* | ||
* | ||
* @param {any} resolve | ||
* | ||
* @memberOf TestCase | ||
*/ | ||
cycling(resolve) { | ||
if (Date.now() - this.startTime < this.time || this.stat.count < this.minSamples) { | ||
for (let i = 0; i < this.cycles; i++) { | ||
this.fn(); | ||
this.stat.count++; | ||
} | ||
}; | ||
if (async) { | ||
this.suite.add(name, { | ||
defer: true, | ||
fn(deferred) { | ||
const res = fn(); | ||
if (res.then) | ||
return fn().then(() => deferred.resolve()); | ||
else | ||
return deferred.resolve(); | ||
}, | ||
onStart | ||
}); | ||
this.stat.cycle++; | ||
setImmediate(() => this.cycling(resolve)); | ||
} else { | ||
this.suite.add(name, { fn, onStart }); | ||
this.finish(); | ||
resolve(this); | ||
} | ||
} | ||
skip() { | ||
return Promise.resolve(); | ||
/** | ||
* | ||
* | ||
* @param {any} resolve | ||
* | ||
* @memberOf TestCase | ||
* | ||
cyclingAsync(resolve, reject) { | ||
const self = this; | ||
const fn = self.fn; | ||
let c = 0; | ||
function cycle() { | ||
return fn().then(() => { | ||
self.stat.count++; | ||
c++; | ||
if (c >= self.cycles) { | ||
if (Date.now() - self.startTime < self.time || self.stat.count < self.minSamples) { | ||
c = 0; | ||
return new Promise(resolve => { | ||
setImmediate(() => resolve(cycle())); | ||
}); | ||
} | ||
} else { | ||
return cycle(); | ||
} | ||
}); | ||
} | ||
return cycle() | ||
.then(() => { | ||
self.finish(); | ||
resolve(self); | ||
}).catch(reject); | ||
}*/ | ||
/** | ||
* | ||
* | ||
* @param {any} resolve | ||
* | ||
* @memberOf TestCase | ||
*/ | ||
cyclingAsyncCb(resolve, reject) { | ||
const self = this; | ||
const fn = self.fn; | ||
let c = 0; | ||
function cycle() { | ||
fn(function() { | ||
self.stat.count++; | ||
c++; | ||
if (c >= self.cycles) { | ||
if (Date.now() - self.startTime < self.time || self.stat.count < self.minSamples) { | ||
// Wait for new cycle | ||
c = 0; | ||
setImmediate(() => cycle()); | ||
} else { | ||
// Finished | ||
self.finish(); | ||
resolve(self); | ||
} | ||
} else { | ||
// Next call | ||
cycle(); | ||
} | ||
}); | ||
} | ||
// Start | ||
cycle(); | ||
} | ||
} | ||
/** | ||
* | ||
* | ||
* @class Suite | ||
*/ | ||
class Suite { | ||
/** | ||
* Creates an instance of Suite. | ||
* @param {any} parent | ||
* @param {any} opts | ||
* | ||
* @memberOf Suite | ||
*/ | ||
constructor(parent, opts) { | ||
this.parent = parent; | ||
this.logger = this.parent.logger; | ||
this.onlyTest = null; | ||
this.done = false; | ||
this.running = false; | ||
this.tests = []; | ||
_.assign(this, { | ||
name: "<Anonymous suite>", | ||
time: 5000, | ||
minSamples: 0 | ||
}, opts); | ||
if (!this.cycles) | ||
this.cycles = this.minSamples > 0 ? this.minSamples : 1000; | ||
} | ||
/** | ||
* | ||
* | ||
* @param {any} name | ||
* @param {any} fn | ||
* @param {any} opts | ||
* @returns | ||
* | ||
* @memberOf Suite | ||
*/ | ||
appendTest(name, fn, opts) { | ||
const test = new TestCase(this, name, fn, opts); | ||
this.tests.push(test); | ||
return test; | ||
} | ||
/** | ||
* | ||
* | ||
* @param {any} name | ||
* @param {any} fn | ||
* @param {any} [opts={}] | ||
* @returns | ||
* | ||
* @memberOf Suite | ||
*/ | ||
add(name, fn, opts = {}) { | ||
this.appendTest(name, fn, opts); | ||
return this; | ||
} | ||
/** | ||
* | ||
* | ||
* @param {any} name | ||
* @param {any} fn | ||
* @param {any} [opts={}] | ||
* @returns | ||
* | ||
* @memberOf Suite | ||
*/ | ||
only(name, fn, opts = {}) { | ||
this.onlyTest = this.appendTest(name, fn, opts); | ||
return this; | ||
} | ||
/** | ||
* | ||
* | ||
* @param {any} name | ||
* @param {any} fn | ||
* @param {any} [opts={}] | ||
* @returns | ||
* | ||
* @memberOf Suite | ||
*/ | ||
skip(name, fn, opts = {}) { | ||
const test = this.appendTest(name, fn, opts); | ||
test.skip = true; | ||
return this; | ||
} | ||
/** | ||
* | ||
* | ||
* @param {any} name | ||
* @param {any} fn | ||
* @param {any} [opts={}] | ||
* @returns | ||
* | ||
* @memberOf Suite | ||
*/ | ||
ref(name, fn, opts = {}) { | ||
const test = this.appendTest(name, fn, opts); | ||
test.reference = true; | ||
return this; | ||
} | ||
/** | ||
* | ||
* | ||
* @returns | ||
* | ||
* @memberOf Suite | ||
*/ | ||
run() { | ||
let self = this; | ||
self.maxTitleLength = this.tests.reduce((max, test) => Math.max(max, test.name.length), 0) + 2; | ||
if (this.onlyTest) { | ||
this.tests.forEach(test => test.skip = test !== this.onlyTest); | ||
} | ||
return new Promise((resolve, reject) => { | ||
this.suite.on("cycle", function(event) { | ||
let bench = event.target; | ||
if (bench.error) | ||
self.logger.error(chalk.red.bold(String(bench), bench.error.message, "\n", bench.error.stack || "")); | ||
else { | ||
if (self.opts.spinner !== false) | ||
spinner.succeed(String(bench)); | ||
else | ||
self.logger.log("››", String(bench)); | ||
} | ||
}) | ||
.on("complete", function() { | ||
self.logger.log(""); | ||
let tests = this.filter("successful"); | ||
let maxTitle = tests.reduce((a, b) => a.name.length > b.name.length ? a : b).name; | ||
let fastest = this.filter("fastest")[0]; | ||
let pe = _.padEnd; | ||
let ps = _.padStart; | ||
self.running = true; | ||
self.logger.log(chalk.magenta.bold(`Suite: ${self.name}`)); | ||
tests.forEach(bench => { | ||
const c = bench == fastest ? chalk.green : chalk.cyan; | ||
let diff = ((bench.hz / fastest.hz) * 100) - 100; | ||
let line = [ | ||
" ", | ||
pe(bench.name, maxTitle.length + 1), | ||
ps(Number(diff).toFixed(2) + "%", 8), | ||
ps(" (" + Benchmark.formatNumber(bench.hz.toFixed(0)) + " ops/sec)", 20) | ||
]; | ||
self.logger.log(c.bold(...line)); | ||
}); | ||
self.logger.log("-----------------------------------------------------------------------\n"); | ||
this.runTest(Array.from(this.tests), resolve); | ||
if (self.opts.spinner !== false) | ||
spinner.stop(); | ||
}).then(() => { | ||
if (self.parent.spinner) | ||
self.parent.spinner.stop(); | ||
let results = { | ||
name: self.opts.name | ||
}; | ||
self.logger.log(""); | ||
results.tests = tests.map(bench => ({ | ||
name: bench.name, | ||
count: bench.hz | ||
})); | ||
// Generate results | ||
return self.calculateResult(); | ||
}); | ||
} | ||
results.timestamp = Date.now(); | ||
results.generated = new Date().toString(); | ||
/** | ||
* | ||
* | ||
* @param {any} list | ||
* @param {any} resolve | ||
* @returns | ||
* | ||
* @memberOf Suite | ||
*/ | ||
runTest(list, resolve) { | ||
const self = this; | ||
const test = list.shift(); | ||
return resolve(results); | ||
}); | ||
function printAndRun(type, msg, err) { | ||
if (self.parent.spinner) | ||
self.parent.spinner[type](msg); | ||
else | ||
self.logger.log("››", msg); | ||
this.logger.log(chalk.magenta.bold("Suite:", this.opts.name)); | ||
this.suite.run({ | ||
defer: this.async, | ||
async: this.async | ||
}); | ||
if (err) | ||
self.logger.error(err); | ||
return list.length > 0 ? self.runTest(list, resolve) : resolve(); | ||
} | ||
if (test.skip) { | ||
// Skip test | ||
return printAndRun("warn", chalk.yellow("[SKIP] " + test.name)); | ||
} | ||
if (this.parent.spinner) { | ||
// Refresh spinner | ||
self.parent.spinner.text = `Running '${test.name}'...`; | ||
self.parent.spinner.start(); | ||
} | ||
// Run test | ||
return test.run().delay(200).then(() => { | ||
const flag = test.async ? "*" : ""; | ||
let msg = _.padEnd(test.name + flag, self.maxTitleLength) + _.padStart(formatNumber(test.stat.rps) + " rps", 20); | ||
return printAndRun("succeed", msg); | ||
}).catch(err => { | ||
test.error = err; | ||
return printAndRun("fail", chalk.red("[ERR] " + test.name), err); | ||
}) | ||
} | ||
/** | ||
* | ||
* | ||
* @returns | ||
* | ||
* @memberOf Suite | ||
*/ | ||
calculateResult() { | ||
let maxRps = 0; | ||
let maxTitleLength = 0; | ||
let fastest = null; | ||
let reference = null; | ||
this.tests.forEach(test => { | ||
if (test.skip) return; | ||
if (test.reference) | ||
reference = test; | ||
if (test.stat.rps > maxRps) { | ||
maxRps = test.stat.rps; | ||
fastest = test; | ||
} | ||
if (test.name.length > maxTitleLength) | ||
maxTitleLength = test.name.length; | ||
}); | ||
//this.tests.sort((a, b) => b.stat.rps - a.stat.rps); | ||
let pe = _.padEnd; | ||
let ps = _.padStart; | ||
this.tests.forEach(test => { | ||
if (test.skip) { | ||
this.logger.log(chalk.yellow(" ", test.name, "(skipped)")); | ||
return; | ||
} | ||
if (test.error) { | ||
this.logger.log(chalk.red(" ", test.name, "(error: " + test.error.message + ")")); | ||
return; | ||
} | ||
const baseRps = reference ? reference.stat.rps : fastest.stat.rps; | ||
const c = test == fastest ? chalk.green : chalk.cyan; | ||
test.stat.percent = ((test.stat.rps / baseRps) * 100) - 100; | ||
let flag = test.async ? "*" : ""; | ||
if (test == reference) | ||
flag += " (#)"; | ||
let line = [ | ||
" ", | ||
pe(test.name + flag, maxTitleLength + 1), | ||
ps(formatNumber(test.stat.percent, 2, true) + "%", 8), | ||
ps(" (" + formatNumber(test.stat.rps) + " rps)", 20), | ||
" (avg: " + humanize.short(test.stat.avg * 1000) + ")" | ||
]; | ||
this.logger.log(c.bold(...line)); | ||
}); | ||
this.logger.log("-----------------------------------------------------------------------\n"); | ||
// Generate result to return | ||
const result = this.tests.map(test => { | ||
let item = { | ||
name: test.name, | ||
reference: test.reference | ||
} | ||
if (test === fastest) | ||
item.fastest = true; | ||
if (test.error) | ||
item.error = test.error.toString(); | ||
if (!test.skip) | ||
item.stat = test.stat; | ||
else | ||
item.skipped = true; | ||
return item; | ||
}); | ||
return result; | ||
} | ||
} | ||
static printHeader(name, logger, platformInfo = true) { | ||
logger = logger || console; | ||
/** | ||
* | ||
* | ||
* @class Benchmarkify | ||
*/ | ||
class Benchmarkify { | ||
/** | ||
* Creates an instance of Benchmarkify. | ||
* @param {any} name | ||
* @param {any} logger | ||
* | ||
* @memberOf Benchmarkify | ||
*/ | ||
constructor(name, opts = {}) { | ||
this.name = name; | ||
this.logger = opts.logger || console; | ||
if (opts.spinner !== false) { | ||
this.spinner = ora({ | ||
text: 'Running benchmark...', | ||
spinner: { | ||
interval: 400, | ||
"frames": [ | ||
". ", | ||
".. ", | ||
"...", | ||
" ..", | ||
" .", | ||
" " | ||
] | ||
} | ||
}); | ||
} | ||
let title = " " + name + " "; | ||
this.Promise = Promise; | ||
this.suites = []; | ||
} | ||
/** | ||
* | ||
* | ||
* | ||
* @memberOf Benchmarkify | ||
*/ | ||
printPlatformInfo() { | ||
require("./platform")(this.logger); | ||
this.logger.log(""); | ||
} | ||
/** | ||
* | ||
* | ||
* @param {boolean} [platformInfo=true] | ||
* | ||
* @memberOf Benchmarkify | ||
*/ | ||
printHeader(platformInfo = true) { | ||
let title = " " + this.name + " "; | ||
let lines = "=".repeat(title.length); | ||
logger.log(chalk.yellow.bold(lines)); | ||
logger.log(chalk.yellow.bold(title)); | ||
logger.log(chalk.yellow.bold(lines)); | ||
logger.log(""); | ||
this.logger.log(chalk.yellow.bold(lines)); | ||
this.logger.log(chalk.yellow.bold(title)); | ||
this.logger.log(chalk.yellow.bold(lines)); | ||
this.logger.log(""); | ||
if (platformInfo) { | ||
require("./platform")(logger); | ||
logger.log(""); | ||
} | ||
if (platformInfo) | ||
this.printPlatformInfo(); | ||
return this; | ||
} | ||
static run(suites) { | ||
let list = Array.from(suites); | ||
/** | ||
* | ||
* | ||
* @param {any} opts | ||
* @returns | ||
* | ||
* @memberOf Benchmarkify | ||
*/ | ||
createSuite(opts) { | ||
const suite = new Suite(this, opts); | ||
this.suites.push(suite); | ||
return suite; | ||
} | ||
/** | ||
* | ||
* | ||
* @param {any} suites | ||
* @returns | ||
* | ||
* @memberOf Benchmarkify | ||
*/ | ||
run(suites) { | ||
const self = this; | ||
let list = Array.from(suites || this.suites); | ||
let results = []; | ||
let start = Date.now(); | ||
/** | ||
* | ||
* | ||
* @param {any} suite | ||
* @returns | ||
*/ | ||
function run(suite) { | ||
return suite.run().then(res => { | ||
results.push(res); | ||
results.push({ | ||
name: suite.name, | ||
tests: res | ||
}); | ||
@@ -152,12 +606,16 @@ if (list.length > 0) | ||
return results; | ||
return { | ||
name: self.name, | ||
suites: results, | ||
timestamp: Date.now(), | ||
generated: new Date().toString(), | ||
elapsedMs: Date.now() - start | ||
} | ||
}); | ||
} | ||
return run(list.shift()).then(() => results); | ||
return run(list.shift()); | ||
} | ||
} | ||
Benchmarkify.Promise = Promise; | ||
module.exports = Benchmarkify; |
{ | ||
"name": "benchmarkify", | ||
"version": "1.3.0", | ||
"version": "2.0.0", | ||
"description": "Benchmark runner for NodeJS", | ||
@@ -21,8 +21,8 @@ "main": "index.js", | ||
"dependencies": { | ||
"benchmark": "2.1.3", | ||
"bluebird": "3.4.7", | ||
"bluebird": "3.5.0", | ||
"chalk": "1.1.3", | ||
"lodash": "4.17.4", | ||
"ora": "1.1.0" | ||
"ora": "1.2.0", | ||
"tiny-human-time": "1.2.0" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
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
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
21629
702
12
1
+ Addedtiny-human-time@1.2.0
+ Addedbluebird@3.5.0(transitive)
+ Addedora@1.2.0(transitive)
+ Addedtiny-human-time@1.2.0(transitive)
- Removedbenchmark@2.1.3
- Removedbenchmark@2.1.3(transitive)
- Removedbluebird@3.4.7(transitive)
- Removedora@1.1.0(transitive)
- Removedplatform@1.3.6(transitive)
Updatedbluebird@3.5.0
Updatedora@1.2.0