From 37a88b0f7202e6cff5dea643ac2649b7af68cb98 Mon Sep 17 00:00:00 2001 From: HP Dietz Date: Sun, 11 Aug 2019 19:40:06 +0200 Subject: [PATCH 1/7] Add new features and migration guide. --- README.md | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/README.md b/README.md index 8da13c9..2bfd31a 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,126 @@ JS-Profiler allows you to compare different techniques and functions regarding e `npm i [-g] js-profiler` +## New in version 2 & Migration from v1.x.y to v2.x.y +* `test.description` now containsa _nice_ human readable description. +* `test.codeSample` now contains a short pseudo-code sample of the function under test. +* use `test.code` to access the full source code of the function under test. +* `test.keywords` contains keywords associated with the function under test. + +### Comparison of v2 vs. v1 profile object + +#### Version 1.x.y profile object + +```javascript +// v1 +{ + "name" : "recursion", + "description" : "Recursion variations: Calculating sum of array of integers. Profile contains a simple for-loop for reference.", + "tests" : [ + { + "description" : "for loop sum for reference", + "time" : { + "average" : "1.4923μs", + "minimum" : "1.0970μs", + "maximum" : "38.8230μs" + } + }, + { + "description" : "recursive sum", + "time" : { + "average" : "1080.3024μs", + "minimum" : "703.3320μs", + "maximum" : "10215.1650μs" + } + }, + { + "description" : "tail recursive sum", + "time" : { + "average" : "1041.0375μs", + "minimum" : "704.2790μs", + "maximum" : "16476.7110μs" + } + } + ], + "fastest" : [ + { + "description" : "for loop sum for reference", + "time" : { + "average" : "1.4923μs", + "minimum" : "1.0970μs", + "maximum" : "38.8230μs" + } + } + ] +} +``` + +#### Version 2.x.y profile object + +```javascript +// v2 +{ + "name": "recursion", + "description": "Recursion.", + "tests": [ + { + "description": "for loop sum for reference", + "keywords": [ + "for", + "loop", + "sum" + ], + "codeSample": "for (...) { sum += d[i] }", + "code": "(d) => {\n let sum = 0;\n for (let i = 0; i < d.length; i++) {\n sum += d[i];\n }\n\n return sum;\n }", + "time": { + "average": "2.8409µs" + } + }, + { + "description": "recursive sum", + "keywords": [ + "recursion", + "sum" + ], + "codeSample": "const f = (d) => (d && d.length && (d[0] + f(d.slice(1)))) || 0", + "code": "(d) => (d && d.length && (d[0] + recursiveSum.f(d.slice(1)))) || 0", + "time": { + "average": "735.3804µs" + } + }, + { + "description": "tail recursive sum", + "keywords": [ + "recursion", + "sum", + "tail", + "tailrecursion" + ], + "codeSample": "const f = (d, i = 0) => (!d.length && i) || f(d.slice(1), i + d[0])", + "code": "(d, i = 0) => (!d.length && i)\n || tailRecursiveSum.f(d.slice(1), i + d[0])", + "time": { + "average": "683.1078µs" + } + } + ], + "fastest": [ + { + "description": "for loop sum for reference", + "keywords": [ + "for", + "loop", + "sum" + ], + "codeSample": "for (...) { sum += d[i] }", + "code": "(d) => {\n let sum = 0;\n for (let i = 0; i < d.length; i++) {\n sum += d[i];\n }\n\n return sum;\n }", + "time": { + "average": "2.8409µs" + } + } + ] +} +``` + ## Usage ### CLI From 04a13d7ca054b4618f3c678fcd1bfecfc8ccd86b Mon Sep 17 00:00:00 2001 From: HP Dietz Date: Sun, 11 Aug 2019 22:05:58 +0200 Subject: [PATCH 2/7] Add array support module. --- lib/support/array/array.support.spec.js | 20 ++++++++++++++++++++ lib/support/array/index.js | 7 +++++++ 2 files changed, 27 insertions(+) create mode 100644 lib/support/array/array.support.spec.js create mode 100644 lib/support/array/index.js diff --git a/lib/support/array/array.support.spec.js b/lib/support/array/array.support.spec.js new file mode 100644 index 0000000..53761c2 --- /dev/null +++ b/lib/support/array/array.support.spec.js @@ -0,0 +1,20 @@ +const chai = require('chai'); +const expect = chai.expect; +const arraySupport = require('./'); + +describe('Array support', () => { + describe('unique', () => { + describe('called with array of unique values', () => { + it('returns the same array', () => { + expect(arraySupport.unique([1, 'a', 'b'])).to.have.deep.members([1, 'a', 'b']); + }); + }); + + describe('called with array of duplicate values', () => { + it('returns an array of unique values', () => { + expect(arraySupport.unique([1, 'b', 1, 'a', 'b'])) + .to.have.deep.members([1, 'a', 'b']); + }); + }); + }); +}); diff --git a/lib/support/array/index.js b/lib/support/array/index.js new file mode 100644 index 0000000..573ca27 --- /dev/null +++ b/lib/support/array/index.js @@ -0,0 +1,7 @@ +const unique = (arr) => [ + ...new Set(arr) +]; + +module.exports = { + unique +}; From 942044b9faf90868855c569e3f344b9f3c3b4710 Mon Sep 17 00:00:00 2001 From: HP Dietz Date: Sun, 11 Aug 2019 22:07:24 +0200 Subject: [PATCH 3/7] Rename profile.tests to profile.functions. Add human readable descriptions to profile functions. Add keywords to profile functions. Add codeSample to profile functions. Add strict vs. equal comparisons to guards profile. Improve test descriptions. Add keywords to profiles. --- lib/profiles/array-concat/index.js | 123 +++++- lib/profiles/comparisons/index.js | 143 +++++-- lib/profiles/guards/guards.profile.spec.js | 16 +- lib/profiles/guards/index.js | 405 ++++++++++++++++-- lib/profiles/loops/index.js | 146 ++++++- lib/profiles/loops/loops.profile.spec.js | 6 +- lib/profiles/map-access/index.js | 33 +- .../map-access/map-access.profile.spec.js | 2 +- lib/profiles/map-creation/index.js | 90 +++- .../map-creation/map-creation.profile.spec.js | 8 +- lib/profiles/object-iteration/index.js | 147 ++++++- .../object-iteration.profile.spec.js | 4 +- lib/profiles/recursion/index.js | 58 +-- .../recursion/recursion.profile.spec.js | 4 +- 14 files changed, 998 insertions(+), 187 deletions(-) diff --git a/lib/profiles/array-concat/index.js b/lib/profiles/array-concat/index.js index 4ca1e55..87f5e00 100644 --- a/lib/profiles/array-concat/index.js +++ b/lib/profiles/array-concat/index.js @@ -1,12 +1,29 @@ +const unique = require('../../support/array').unique; + const concat = { - description: 'a.concat(b)', - f: (d) => { - return d[0].concat(d[1]); - } + description: 'Array\'s concat() method', + keywords: [ + 'array', + 'concat', + 'concatenation', + 'method' + ].sort(), + codeSample: 'a.concat(b)', + f: (d) => d[0].concat(d[1]) }; const concatForPush = { - description: 'for (...) { a.push(b[i]) }', + description: 'append elements in a for loop', + keywords: [ + 'array', + 'concatenation', + 'for', + 'loop', + 'push', + 'append', + 'insert' + ].sort(), + codeSample: 'for (...) { a.push(b[i]) }', f: (d) => { for (let i = 0; i < d[1].length; i++) { d[0].push(d[1][i]); @@ -17,7 +34,17 @@ const concatForPush = { }; const concatForUnshift = { - description: 'for (...) { b.unshift(a[i]) }', + description: 'prepend elements in a foor loop', + keywords: [ + 'array', + 'concatenation', + 'for', + 'loop', + 'unshift', + 'prepend', + 'insert' + ].sort(), + codeSample: 'for (...) { b.unshift(a[i]) }', f: (d) => { for (let i = d[0].length - 1; i >= 0; i--) { d[1].unshift(d[0][i]); @@ -28,7 +55,16 @@ const concatForUnshift = { }; const concatApplyPush = { - description: 'a.push.apply(a, b)', + description: 'append elements using apply()', + keywords: [ + 'array', + 'concatenation', + 'apply', + 'push', + 'append', + 'insert' + ].sort(), + codeSample: 'a.push.apply(a, b)', f: (d) => { d[0].push.apply(d[0], d[1]); return d[0]; @@ -36,7 +72,16 @@ const concatApplyPush = { }; const concatApplyUnshift = { - description: 'b.unshift.apply(b, a)', + description: 'prepend elements using apply()', + keywords: [ + 'array', + 'concatenation', + 'apply', + 'unshift', + 'prepend', + 'insert' + ].sort(), + codeSample: 'b.unshift.apply(b, a)', f: (d) => { d[1].unshift.apply(d[1], d[0]); return d[1]; @@ -44,7 +89,16 @@ const concatApplyUnshift = { }; const concatReduce = { - description: 'b.reduce((arr, item) => arr.push(item), a)', + description: 'append elements using reduce()', + keywords: [ + 'array', + 'concatenation', + 'reduce', + 'push', + 'append', + 'insert' + ].sort(), + codeSample: 'b.reduce((arr, item) => arr.push(item), a)', f: (d) => d[1].reduce((r, i) => { r.push(i); return r; @@ -52,33 +106,58 @@ const concatReduce = { }; const concatReduceRight = { - description: 'a.reduceRight((arr, item) => arr.unshift(item), b)', + description: 'prepend elements using reduceRight()', + keywords: [ + 'array', + 'concatenation', + 'reduce', + 'reduceright', + 'unshift', + 'prepend', + 'insert' + ].sort(), + codeSample: 'a.reduceRight((arr, item) => arr.unshift(item), b)', f: (d) => d[0].reduceRight((r, i) => { r.unshift(i); return r; }, d[1]) }; -const concatSpread = { - description: '[...a, ...b]', +const concatPrependSpread = { + description: 'prepend elements using array spread syntax', + keywords: [ + 'array', + 'concatenation', + 'spread', + 'syntax', + 'prepend', + 'insert' + ].sort(), + codeSample: '[...a, ...b]', f: (d) => [...d[0], ...d[1]] }; +const functions = [ + concat, + concatForPush, + concatForUnshift, + concatApplyPush, + concatApplyUnshift, + concatReduce, + concatReduceRight, + concatPrependSpread +]; + module.exports = { name: 'Array concatenation', description: { long: 'Array concatenation variations: Combining two arrays using different techniques.', short: 'Array concatenation variations.' }, - functions: [ - concat, - concatForPush, - concatForUnshift, - concatApplyPush, - concatApplyUnshift, - concatReduce, - concatReduceRight, - concatSpread - ], + keywords: unique( + functions.map((fn) => fn.keywords) + .reduce((keywords, fnKeywords) => [...keywords, ...fnKeywords]) + ).sort(), + functions, testDataType: 'arrays' }; diff --git a/lib/profiles/comparisons/index.js b/lib/profiles/comparisons/index.js index 81dbac4..a869b31 100644 --- a/lib/profiles/comparisons/index.js +++ b/lib/profiles/comparisons/index.js @@ -1,71 +1,156 @@ +const unique = require('../../support/array').unique; const compGreater = { - description: 'a > b', + description: '>, greater than', + keywords: [ + 'comparison', + 'greater', + 'operator' + ].sort(), + codeSample: 'a > b', f: (d) => d > 5 }; const compGreaterEqual = { - description: 'a >= b', + description: '>=, greater than or equal to', + keywords: [ + 'comparison', + 'greater', + 'equal', + 'operator' + ].sort(), + codeSample: 'a >= b', f: (d) => d >= 5 -} +}; const compLess = { - description: 'a < b', + description: '<, less than', + keywords: [ + 'comparison', + 'less', + 'operator' + ].sort(), + codeSample: 'a < b', f: (d) => d < 5 }; const compLessEqual = { - description: 'a <= b', + description: '<=,less than or equal to', + keywords: [ + 'comparison', + 'less', + 'equal', + 'operator' + ].sort(), + codeSample: 'a <= b', f: (d) => d <= 5 }; -const compEql = { - description: 'a == b', - f: (d) => d == 5 +const compEqlLoose = { + description: '==, loose equality', + keywords: [ + 'comparison', + 'equal', + 'loose', + 'equality' + ].sort(), + codeSample: 'a == b', + f: (d) => d == 5 // eslint-disable-line eqeqeq }; -const compEqual = { - description: 'a === b', +const compEqlStrict = { + description: '===, strict equality, identity, tripple equals', + keywords: [ + 'comparison', + 'equal', + 'strict', + 'equality', + 'identity', + 'tripple', + 'equals', + 'type' + ].sort(), + codeSample: 'a === b', f: (d) => d === 5 }; -const compNotEql = { - description: 'a != b', - f: (d) => d != 5 +const compNotEqlLoose = { + description: '!=, loose non-equality', + keywords: [ + 'comparison', + 'equal', + 'loose', + 'equality', + 'not', + 'nonequal' + ].sort(), + codeSample: 'a != b', + f: (d) => d != 5 // eslint-disable-line eqeqeq }; -const compNotEqual = { - description: 'a !== b', +const compNotEqlStrict = { + description: '!==, strict non-equality', + keywords: [ + 'comparison', + 'equal', + 'strict', + 'equality', + 'not', + 'nonequal' + ].sort(), + codeSample: 'a !== b', f: (d) => d !== 5 }; const compAnd = { - description: 'a && b', + description: '&&, logical and operator', + keywords: [ + 'comparison', + 'logical', + 'and', + 'boolean', + 'operator' + ].sort(), + codeSample: 'a && b', f: (d) => d && d - 5 }; const compOr = { - description: 'a || b', + description: '||, logical or operator', + keywords: [ + 'comparison', + 'logical', + 'or', + 'boolean', + 'operator' + ].sort(), + codeSample: 'a || b', f: (d) => d || d - 5 }; +const functions = [ + compGreater, + compGreaterEqual, + compLess, + compLessEqual, + compEqlLoose, + compEqlStrict, + compNotEqlLoose, + compNotEqlStrict, + compAnd, + compOr +]; + module.exports = { name: 'comparison operators', description: { long: 'Variable comparison operators.', short: 'Comparison operators.' }, - functions: [ - compGreater, - compGreaterEqual, - compLess, - compLessEqual, - compEql, - compEqual, - compNotEql, - compNotEqual, - compAnd, - compOr - ], + keywords: unique( + functions.map((fn) => fn.keywords) + .reduce((keywords, fnKeywords) => [...keywords, ...fnKeywords]) + ).sort(), + functions, testDataType: 'number' }; diff --git a/lib/profiles/guards/guards.profile.spec.js b/lib/profiles/guards/guards.profile.spec.js index 4642c71..245db26 100644 --- a/lib/profiles/guards/guards.profile.spec.js +++ b/lib/profiles/guards/guards.profile.spec.js @@ -8,7 +8,8 @@ describe('Guards', () => { data = { num: 1, arr: [], - str: 'abc' + str: 'abc', + fn: () => 1 }; }); @@ -18,14 +19,17 @@ describe('Guards', () => { result = fn.f(data); }); - it('should return a boolean', () => { + it('returns a boolean', () => { expect(typeof result).to.equal('boolean'); }); - it('should transform the array correctly into booleans', () => { - if (fn.description === '!var' - || fn.description === 'Array.isArray' - || fn.description === 'typeof === type') { + it('transforms the array correctly into booleans', () => { + if (fn.codeSample === '!var' + || fn.codeSample === 'Array.isArray(d)' + || /typeof d === (?!'object')/.test(fn.codeSample) + || /^Number.isNaN/.test(fn.codeSample) + || /^!isNaN/.test(fn.codeSample) + || /typeof d == (?!'object')/.test(fn.codeSample)) { expect(result).to.be.false; } else { expect(result).to.be.true; diff --git a/lib/profiles/guards/index.js b/lib/profiles/guards/index.js index 67a329d..98180f6 100644 --- a/lib/profiles/guards/index.js +++ b/lib/profiles/guards/index.js @@ -1,64 +1,417 @@ -const guardTypeofNotUndefined = { - description: 'typeof !== undefined', +const unique = require('../../support/array').unique; + +const guardStrictTypeofNotUndefined = { + description: 'strict comparison using typeof against \'undefined\'', + keywords: [ + 'check', + 'typeof', + 'strict', + 'comparison', + 'triple equals', + 'identity', + 'type', + 'undefined', + 'defined', + 'equality', + 'operator' + ].sort(), + codeSample: 'typeof d !== \'undefined\'', f: (d) => typeof d !== 'undefined' }; -const guardTypeofIsType = { - description: 'typeof === type', +const guardLooseTypeofNotUndefined = { + description: 'loose comparison using typeof against \'undefined\'', + keywords: [ + 'check', + 'typeof', + 'loose', + 'comparison', + 'triple equals', + 'identity', + 'type', + 'undefined', + 'defined', + 'equality', + 'operator' + ].sort(), + codeSample: 'typeof d != \'undefined\'', + f: (d) => typeof d != 'undefined' // eslint-disable-line eqeqeq +}; + +const guardStrictDefined = { + description: 'strict comparison against null and undefined', + keywords: [ + 'check', + 'equality', + 'strict', + 'comparison', + 'tripple equals', + 'identity', + 'null', + 'undefined', + 'defined', + 'operator' + ].sort(), + codeSample: '!(d === undefined || d === null)', + f: (d) => !(d === undefined || d === null) +}; + +const guardLooseDefined = { + description: 'loose comparison against null and undefined', + keywords: [ + 'check', + 'equality', + 'loose', + 'comparison', + 'tripple equals', + 'identity', + 'null', + 'undefined', + 'defined', + 'operator' + ].sort(), + codeSample: '!(d == undefined || d == null)', + f: (d) => !(d == undefined || d == null) // eslint-disable-line eqeqeq +}; + +const guardStrictTypeofIsTypeNumber = { + description: 'strict comparison using typeof against \'number\'', + keywords: [ + 'strict', + 'comparison', + 'equality', + 'tripple equals', + 'identity', + 'number', + 'typeof', + 'type', + 'operator' + ].sort(), + codeSample: 'typeof d === \'number\'', f: (d) => typeof d === 'number' }; +const guardLooseTypeofIsTypeNumber = { + description: 'loose comparison using typeof against \'number\'', + keywords: [ + 'loose', + 'comparison', + 'equality', + 'tripple equals', + 'identity', + 'number', + 'typeof', + 'type', + 'operator' + ].sort(), + codeSample: 'typeof d == \'number\'', + f: (d) => typeof d == 'number' // eslint-disable-line eqeqeq +}; + +const guardStrictTypeofIsTypeString = { + description: 'strict comparison using typeof against \'string\'', + keywords: [ + 'strict', + 'comparison', + 'equality', + 'tripple equals', + 'identity', + 'string', + 'typeof', + 'type', + 'operator' + ].sort(), + codeSample: 'typeof d === \'string\'', + f: (d) => typeof d === 'string' +}; + +const guardLooseTypeofIsTypeString = { + description: 'loose comparison using typeof against \'string\'', + keywords: [ + 'loose', + 'comparison', + 'equality', + 'tripple equals', + 'identity', + 'string', + 'typeof', + 'type', + 'operator' + ].sort(), + codeSample: 'typeof d == \'string\'', + f: (d) => typeof d == 'string' // eslint-disable-line eqeqeq +}; + +const guardStrictTypeofIsTypeObject = { + description: 'strict comparison using typeof against \'object\'', + keywords: [ + 'strict', + 'equality', + 'comparison', + 'tripple equals', + 'identity', + 'object', + 'typeof', + 'type', + 'operator' + ].sort(), + codeSample: 'typeof d === \'object\'', + f: (d) => typeof d === 'object' +}; + +const guardLooseTypeofIsTypeObject = { + description: 'loose comparison using typeof against \'object\'', + keywords: [ + 'loose', + 'equality', + 'comparison', + 'tripple equals', + 'identity', + 'object', + 'typeof', + 'type', + 'operator' + ].sort(), + codeSample: 'typeof d === \'object\'', + f: (d) => typeof d == 'object' // eslint-disable-line eqeqeq +}; + +const guardStrictTypeofIsTypeFunction = { + description: 'strict comparison using typeof against \'function\'', + keywords: [ + 'strict', + 'equality', + 'comparison', + 'tripple equals', + 'identity', + 'function', + 'typeof', + 'type', + 'operator' + ].sort(), + codeSample: 'typeof d === \'function\'', + f: (d) => typeof d === 'function' +}; + +const guardLooseTypeofIsTypeFunction = { + description: 'loose comparison using typeof against \'function\'', + keywords: [ + 'loose', + 'equality', + 'comparison', + 'tripple equals', + 'identity', + 'function', + 'typeof', + 'type', + 'operator' + ].sort(), + codeSample: 'typeof d == \'function\'', + f: (d) => typeof d == 'function' // eslint-disable-line eqeqeq +}; + const guardIsArray = { - description: 'Array.isArray', + description: 'Array\'s isArray() method', + keywords: [ + 'equality', + 'comparison', + 'identity', + 'type', + 'array', + 'isArray', + 'method' + ].sort(), + codeSample: 'Array.isArray(d)', f: (d) => Array.isArray(d) }; const guardNotNot = { - description: '!!var', + description: 'double negation, !!, "not, not"', + keywords: [ + 'not', + 'notnot', + '!', + '!!', + 'defined', + 'type', + 'negation', + 'double', + 'bool', + 'boolean', + 'operator' + ].sort(), + codeSample: '!!var', f: (d) => !!d }; const guardNot = { - description: '!var', + description: 'negation, !, "not"', + keywords: [ + 'not', + '!', + 'defined', + 'type', + 'negation', + 'operator', + 'bool', + 'boolean' + ].sort(), + codeSample: '!var', f: (d) => !d }; -const guardNotIsNaN = { - description: '!isNaN(var)', +const guardGlobalNotIsNaN = { + description: 'negated global isNaN()', + keywords: [ + 'not', + 'nan', + 'not a number', + 'number', + 'defined', + 'type', + 'isnan', + 'global', + 'method' + ].sort(), + codeSample: '!isNaN(var)', f: (d) => !isNaN(d) }; -const guardIsNaN = { - description: 'isNaN(var)', +const guardNumberNotIsNaN = { + description: 'negated Number\'s isNaN() method', + keywords: [ + 'not', + 'nan', + 'not a number', + 'number', + 'defined', + 'type', + 'isnan', + 'method' + ].sort(), + codeSample: '!Number.isNaN(var)', + f: (d) => !Number.isNaN(d) +}; + +const guardGlobalIsNaN = { + description: 'global isNaN() method', + keywords: [ + 'number', + 'defined', + 'type', + 'isnan', + 'not a number', + 'not', + 'global', + 'method' + ].sort(), + codeSample: 'isNaN(var)', f: (d) => isNaN(d) -} +}; + +const guardNumberIsNaN = { + description: 'Number\'s isNaN() method', + keywords: [ + 'number', + 'defined', + 'type', + 'isnan', + 'not a number', + 'not', + 'method' + ].sort(), + codeSample: 'Number.isNaN(var)', + f: (d) => Number.isNaN(d) +}; const guardIn = { - description: 'prop in obj', + description: 'the \'in\' operator', + keywords: [ + 'in', + 'property', + 'existence', + 'prop', + 'object', + 'defined', + 'type', + 'operator' + ].sort(), + codeSample: 'prop in obj', f: (d) => 'num' in d, testDataType: 'object' }; -const guardHasOwnProperty = { - description: 'obj.hasOwnProperty(prop)', - f: (d) => d.hasOwnProperty('num'), +const guardTargetHasOwnProperty = { + description: 'Object\'s hasOwnProperty() method called on target', + keywords: [ + 'property', + 'existence', + 'prop', + 'object', + 'defined', + 'type', + 'hasownproperty', + 'method', + 'target', + 'prototype' + ].sort(), + codeSample: 'obj.hasOwnProperty(prop)', + f: (d) => d.hasOwnProperty('num'), // eslint-disable-line no-prototype-builtins testDataType: 'object' }; +const guardObjectHasOwnProperty = { + description: 'Object\'s hasOwnProperty() method called from Object prototype', + keywords: [ + 'property', + 'existence', + 'prop', + 'object', + 'defined', + 'type', + 'hasownproperty', + 'method', + 'prototype' + ].sort(), + codeSample: 'Object.prototype.hasOwnProperty.call(obj, prop)', + f: (d) => Object.prototype.hasOwnProperty.call(d, 'num'), + testDataType: 'object' +}; + +const functions = [ + guardStrictTypeofNotUndefined, + guardLooseTypeofNotUndefined, + guardStrictTypeofIsTypeFunction, + guardLooseTypeofIsTypeFunction, + guardStrictTypeofIsTypeNumber, + guardLooseTypeofIsTypeNumber, + guardStrictTypeofIsTypeObject, + guardLooseTypeofIsTypeObject, + guardStrictTypeofIsTypeString, + guardLooseTypeofIsTypeString, + guardIsArray, + guardNotNot, + guardNot, + guardGlobalIsNaN, + guardNumberIsNaN, + guardGlobalNotIsNaN, + guardNumberNotIsNaN, + guardIn, + guardTargetHasOwnProperty, + guardObjectHasOwnProperty, + guardStrictDefined, + guardLooseDefined +]; + module.exports = { name: 'guards', description: { short: 'Variable guards.', long: 'Variable guards: checking whether a variable is defined or of a certain type.' }, - functions: [ - guardTypeofNotUndefined, - guardTypeofIsType, - guardIsArray, - guardNotNot, - guardNot, - guardIsNaN, - guardIn, - guardHasOwnProperty - ] + keywords: unique( + functions.map((fn) => fn.keywords) + .reduce((keywords, fnKeywords) => [...keywords, ...fnKeywords]) + ).sort(), + functions }; diff --git a/lib/profiles/loops/index.js b/lib/profiles/loops/index.js index ad74d77..4231c20 100644 --- a/lib/profiles/loops/index.js +++ b/lib/profiles/loops/index.js @@ -1,5 +1,15 @@ +const unique = require('../../support/array').unique; + const loopForEach = { - description: '[].forEach() => []', + description: 'forEach loop', + keywords: [ + 'foreach', + 'loop', + 'push', + 'array', + 'iteration' + ].sort(), + codeSample: '[].forEach((d) => [].push(d)) => []', f: (d) => { const r = []; d.forEach((dp) => r.push(dp < 5 && dp > 3)); @@ -8,7 +18,15 @@ const loopForEach = { }; const loopFor = { - description: 'for(i < d.length; i++) => []', + description: 'for loop', + keywords: [ + 'for', + 'loop', + 'push', + 'array', + 'iteration' + ].sort(), + codeSample: 'for(i < d.length; i++) { [].push(d[i]) } => []', f: (d) => { const r = []; let dp; @@ -22,7 +40,17 @@ const loopFor = { }; const loopForFixedLen = { - description: 'for(i < len; i++) => []', + description: 'for loop with length variable', + keywords: [ + 'for', + 'loop', + 'push', + 'length', + 'variable', + 'array', + 'iteration' + ].sort(), + codeSample: 'for(i < len; i++) { [].push(d[i]) } => []', f: (d) => { const r = []; const len = d.length; @@ -37,7 +65,16 @@ const loopForFixedLen = { }; const loopInverseWhile = { - description: 'while(i--) => []', + description: 'inverse while loop', + keywords: [ + 'while', + 'loop', + 'inverse', + 'push', + 'array', + 'iteration' + ].sort(), + codeSample: 'while(i--) { [].push(d[i]) } => []', f: (d) => { const r = []; let i = d.length; @@ -52,7 +89,16 @@ const loopInverseWhile = { }; const loopWhile = { - description: 'while(i < d.length) => []', + description: 'while loop', + keywords: [ + 'while', + 'loop', + 'inverse', + 'push', + 'array', + 'iteration' + ].sort(), + codeSample: 'while(i < d.length) { [].push(d[i]) } => []', f: (d) => { const r = []; let i = 0; @@ -68,7 +114,17 @@ const loopWhile = { }; const loopWhileFixedLen = { - description: 'while(i < len) => []', + description: 'while loop with length variable', + keywords: [ + 'while', + 'loop', + 'length', + 'variable', + 'push', + 'array', + 'iteration' + ].sort(), + codeSample: 'while(i < len) { [].push(d[i]) } => []', f: (d) => { const r = []; const len = d.length; @@ -85,7 +141,16 @@ const loopWhileFixedLen = { }; const loopWhileDo = { - description: 'do { } while (i < d.length) => []', + description: 'do while loop', + keywords: [ + 'do', + 'while', + 'loop', + 'push', + 'array', + 'iteration' + ].sort(), + codeSample: 'do { [].push(d[i]) } while (i < d.length) => []', f: (d) => { const r = []; let i = 0; @@ -101,7 +166,18 @@ const loopWhileDo = { }; const loopWhileDoFixedLen = { - description: 'do { } while (i < len) => []', + description: 'do while loop with length variable', + keywords: [ + 'do', + 'while', + 'loop', + 'push', + 'length', + 'variable', + 'iteration', + 'array' + ].sort(), + codeSample: 'do { [].push(d[i]) } while (i < len) => []', f: (d) => { const r = []; let i = 0; @@ -118,15 +194,33 @@ const loopWhileDoFixedLen = { }; const loopMap = { - description: '[].map() => []', + description: 'map', + keywords: [ + 'map', + 'loop', + 'iteration', + 'array' + ].sort(), + codeSample: '[].map() => []', f: (d) => d.map((dp) => dp < 5 && dp > 3) }; const loopForOf = { - description: 'for (prop of []) => []', + description: 'for of loop', + keywords: [ + 'for', + 'of', + 'property', + 'object', + 'push', + 'iteration', + 'array', + 'loop' + ].sort(), + codeSample: 'for (prop of []) { [].push(prop) } => []', f: (d) => { const r = []; - for (let p of d) { + for (const p of d) { r.push(p < 5 && p > 3); } @@ -134,23 +228,29 @@ const loopForOf = { } }; +const functions = [ + loopForEach, + loopFor, + loopForFixedLen, + loopForOf, + loopInverseWhile, + loopMap, + loopWhile, + loopWhileFixedLen, + loopWhileDo, + loopWhileDoFixedLen +]; + module.exports = { name: 'loops', description: { long: 'Loop variations: Converting an array of integers into an array of booleans satisfying a conjunction of two simple relational operations.', short: 'Loop variations.' }, - functions: [ - loopForEach, - loopFor, - loopForFixedLen, - loopForOf, - loopInverseWhile, - loopMap, - loopWhile, - loopWhileFixedLen, - loopWhileDo, - loopWhileDoFixedLen - ], + keywords: unique( + functions.map((fn) => fn.keywords) + .reduce((keywords, fnKeywords) => [...keywords, ...fnKeywords]) + ).sort(), + functions, testDataType: 'array' }; diff --git a/lib/profiles/loops/loops.profile.spec.js b/lib/profiles/loops/loops.profile.spec.js index 8ee32bb..10329b9 100644 --- a/lib/profiles/loops/loops.profile.spec.js +++ b/lib/profiles/loops/loops.profile.spec.js @@ -14,17 +14,17 @@ describe('Loops', () => { result = fn.f(data); }); - it('should return an array', () => { + it('returns an array', () => { expect(Array.isArray(result)).to.be.true; }); - it('should return an array of booleans', () => { + it('returns an array of booleans', () => { result.forEach((val) => { expect(val).to.be.a('boolean'); }); }); - it('should transform the integers correctly into booleans', () => { + it('transforms the integers correctly into booleans', () => { expect(result).to.eql([false, false, false, false, true, false]); }); }); diff --git a/lib/profiles/map-access/index.js b/lib/profiles/map-access/index.js index 1eccf32..51fae2f 100644 --- a/lib/profiles/map-access/index.js +++ b/lib/profiles/map-access/index.js @@ -1,26 +1,47 @@ +const unique = require('../../support/array').unique; + const randInt = (max) => Math.floor(Math.random() * Math.floor(max)); const accessMap = { - description: 'Map.get()', + description: 'Map\'s get() method', + keywords: [ + 'map', + 'access', + 'get' + ].sort(), + codeSample: 'Map.get()', f: (d) => d.get(randInt(d.size - 1)), testDataType: 'map' }; const accessObject = { - description: '{}.prop', + description: 'acess object property', + keywords: [ + 'map', + 'access', + 'object', + 'property' + ].sort(), + codeSample: '{}.prop', f: (d) => d[randInt(d.size - 1)], testDataType: 'objectMap' }; +const functions = [ + accessMap, + accessObject +]; + module.exports = { name: 'map:access', description: { long: 'Object literal vs. Map: retrieving values.', short: 'Object literal vs. Map access.' }, - functions: [ - accessMap, - accessObject, - ] + keywords: unique( + functions.map((fn) => fn.keywords) + .reduce((keywords, fnKeywords) => [...keywords, fnKeywords]) + ).sort(), + functions }; diff --git a/lib/profiles/map-access/map-access.profile.spec.js b/lib/profiles/map-access/map-access.profile.spec.js index 0596ac2..96edff4 100644 --- a/lib/profiles/map-access/map-access.profile.spec.js +++ b/lib/profiles/map-access/map-access.profile.spec.js @@ -33,7 +33,7 @@ describe('Object literal vs. Map access', () => { result = fn.f(data[fn.testDataType]); }); - it('should return retrieved value', () => { + it('returns retrieved value', () => { expect(typeof result).to.equal('number'); }); }); diff --git a/lib/profiles/map-creation/index.js b/lib/profiles/map-creation/index.js index 474846f..ece2c4a 100644 --- a/lib/profiles/map-creation/index.js +++ b/lib/profiles/map-creation/index.js @@ -1,5 +1,13 @@ +const unique = require('../../support/array').unique; + const setMap = { - description: 'Map.set()', + description: 'Map.set() in a forEach loop', + keywords: [ + 'map', + 'creation', + 'set' + ].sort(), + codeSample: 'Map.set()', f: (d) => { const m = new Map(); d.forEach((dp, i) => m.set(i, dp)); @@ -8,14 +16,28 @@ const setMap = { }; const createMap = { - description: 'new Map([props])', - f: (d) => { - return new Map(d.map((dp, i, arr) => [i, dp])); - } + description: 'passing key-value pairs to the Map constructor', + keywords: [ + 'map', + 'creation', + 'construtor', + 'key-value', + 'pairs' + ].sort(), + codeSample: 'new Map([props])', + f: (d) => new Map(d.map((dp, i) => [i, dp])) }; const setObject = { - description: '{}.prop =', + description: 'setting properties on an Object literal', + keywords: [ + 'map', + 'creation', + 'object', + 'literal', + 'properties' + ].sort(), + codeSample: '{}.prop = val', f: (d) => { const m = {}; d.forEach((dp, i) => m[i] = dp); @@ -24,7 +46,16 @@ const setObject = { }; const defineProperty = { - description: 'Object.defineProperty({}, prop, desc)', + description: 'Object\'s definePropety() method on an Object literal', + keywords: [ + 'map', + 'creation', + 'object', + 'literal', + 'defineProperty', + 'properties' + ].sort(), + codeSample: 'Object.defineProperty({}, prop, desc)', f: (d) => { const m = {}; d.forEach((dp, i) => @@ -38,7 +69,16 @@ const defineProperty = { }; const defineProperties = { - description: 'Object.defineProperties({}, props)', + description: 'Object\'s defineProperties method on an Object literal', + keywords: [ + 'map', + 'creation', + 'object', + 'literal', + 'defineProperties', + 'properties' + ].sort(), + codeSample: 'Object.defineProperties({}, props)', f: (d) => { const m = {}; Object.defineProperties(m, d.reduce((props, dp, i) => @@ -53,25 +93,41 @@ const defineProperties = { }; const spread = { - description: '{ ...props }', + description: 'object spread syntax', + keywords: [ + 'map', + 'creation', + 'object', + 'literal', + 'spread', + 'syntax', + 'properties' + ].sort(), + codeSample: '{ ...props }', f: (d) => ({ ...d }) }; +const functions = [ + createMap, + defineProperty, + defineProperties, + setMap, + setObject, + spread +]; + module.exports = { name: 'map:creation', description: { long: 'Object literal vs. Map: creating a map.', short: 'Object literal vs. Map creation.' }, - functions: [ - createMap, - defineProperty, - defineProperties, - setMap, - setObject, - spread - ], + keywords: unique( + functions.map((fn) => fn.keywords) + .reduce((keywords, fnKeywords) => [...keywords, ...fnKeywords]) + ).sort(), + functions, testDataType: 'array' }; diff --git a/lib/profiles/map-creation/map-creation.profile.spec.js b/lib/profiles/map-creation/map-creation.profile.spec.js index 2f45e26..c556e9c 100644 --- a/lib/profiles/map-creation/map-creation.profile.spec.js +++ b/lib/profiles/map-creation/map-creation.profile.spec.js @@ -4,7 +4,7 @@ const mapCreation = require('./'); describe('Object literal vs. Map creation', () => { let result; let data; - + beforeEach(() => { data = [0, 1, 2, 3, 4, 5]; }); @@ -15,11 +15,11 @@ describe('Object literal vs. Map creation', () => { result = fn.f(data); }); - it('should return the created object or retrieved value', () => { - expect(typeof result).to.equal('object'); + it('returns the created object or retrieved value', () => { + expect(typeof result).to.equal('object'); }); - it('should contain as many entries as datapoints were supplied', () => { + it('contains as many entries as datapoints were supplied', () => { if (result instanceof Map) { expect(result.size).to.equal(data.length); } else { diff --git a/lib/profiles/object-iteration/index.js b/lib/profiles/object-iteration/index.js index 5a1c4c2..e080be5 100644 --- a/lib/profiles/object-iteration/index.js +++ b/lib/profiles/object-iteration/index.js @@ -1,5 +1,17 @@ +const unique = require('../../support/array').unique; + const forIn = { - description: 'for prop in obj => string', + description: 'for property in object loop', + keywords: [ + 'for', + 'in', + 'property', + 'forin', + 'loop', + 'object', + 'iteration' + ].sort(), + codeSample: 'for (const prop in obj) { } => string', f: (d) => { let s = ''; for (const p in d) { @@ -10,7 +22,16 @@ const forIn = { }; const keys = { - description: 'Object.keys(obj).forEach => string', + description: 'iterating an object\'s keys with forEach', + keywords: [ + 'foreach', + 'loop', + 'iteration', + 'object', + 'keys', + 'property' + ].sort(), + codeSample: 'Object.keys(obj).forEach() => string', f: (d) => { let s = ''; Object.keys(d).forEach((p) => { @@ -21,7 +42,16 @@ const keys = { }; const entries = { - description: 'Object.entries(obj).forEach => string', + description: 'iterating an object\'s entries with forEach', + keywords: [ + 'foreach', + 'loop', + 'iteration', + 'object', + 'entries', + 'property' + ].sort(), + codeSample: 'Object.entries(obj).forEach => string', f: (d) => { let s = ''; Object.entries(d).forEach((e) => { @@ -32,10 +62,21 @@ const entries = { }; const forOfMap = { - description: 'for (prop of Map.keys()) => string', + description: 'iterating a Map\'s keys with for of', + keywords: [ + 'forof', + 'for', + 'of', + 'keys', + 'map', + 'property', + 'loop', + 'iteration' + ].sort(), + codeSample: 'for (prop of Map.keys()) => string', f: (d) => { let s = ''; - for (let p of d.keys()) { + for (const p of d.keys()) { s = `${s}${p}`; } return s; @@ -44,10 +85,21 @@ const forOfMap = { }; const forOfObject = { - description: 'for (prop of Object.keys(obj)) => string', + description: 'iterating an object\'s keys with for of', + keywords: [ + 'forof', + 'for', + 'of', + 'keys', + 'object', + 'property', + 'loop', + 'iteration' + ].sort(), + codeSample: 'for (prop of Object.keys(obj)) => string', f: (d) => { let s = ''; - for (let p of Object.keys(d)) { + for (const p of Object.keys(d)) { s = `${s}${p}`; } return s; @@ -55,11 +107,26 @@ const forOfObject = { }; const forOfObjectChecked = { - description: 'for (prop of Object.keys(obj)) with hasOwnProperty() check => string', + description: 'iterating an object\'s keys in a for of loop with own-property check', + keywords: [ + 'forof', + 'for', + 'of', + 'keys', + 'object', + 'property', + 'loop', + 'iteration', + 'check', + 'hasownperperty', + 'own', + 'ownproperty' + ].sort(), + codeSample: 'for (prop of Object.keys(obj)) { obj.hasOwnProperty(prop) && ... }', f: (d) => { let s = ''; - for (let p of Object.keys(d)) { - if (d.hasOwnProperty(p)) { + for (const p of Object.keys(d)) { + if (d.hasOwnProperty(p)) { // eslint-disable-line s = `${s}${p}`; } } @@ -68,10 +135,25 @@ const forOfObjectChecked = { }; const forOfNames = { - description: 'for (prop of Object.getOwnPropertyNames(obj)) => string', + description: 'iterating an object\'s own property names with for of', + keywords: [ + 'forof', + 'for', + 'of', + 'names', + 'property', + 'own', + 'ownpropertynames', + 'ownprops', + 'ownproperties', + 'getownpropertynames', + 'object', + 'loop' + ].sort(), + codeSample: 'for (prop of Object.getOwnPropertyNames(obj)) => string', f: (d) => { let s = ''; - for (let p of Object.getOwnPropertyNames(d)) { + for (const p of Object.getOwnPropertyNames(d)) { s = `${s}${p}`; } return s; @@ -79,7 +161,21 @@ const forOfNames = { }; const ownPropNames = { - description: 'Object.getOwnPropertyNames(obj).forEach => string', + description: 'iterating an object\'s own property names with forEach', + keywords: [ + 'foreach', + 'names', + 'property', + 'own', + 'names', + 'ownpropertynames', + 'ownprops', + 'ownproperties', + 'getownpropertynames', + 'object', + 'loop' + ].sort(), + codeSample: 'Object.getOwnPropertyNames(obj).forEach() => string', f: (d) => { let s = ''; Object.getOwnPropertyNames(d).forEach((p) => { @@ -89,20 +185,27 @@ const ownPropNames = { } }; +const functions = [ + entries, + forIn, + forOfMap, + forOfNames, + forOfObject, + forOfObjectChecked, + keys, + ownPropNames +]; + module.exports = { name: 'object iteration', description: { long: 'Object iteration: different ways of iterating over properties of an object and concatenating property names into a single string.', short: 'Object iteration: concatenating property names into a string.' }, - functions: [ - entries, - forIn, - forOfMap, - forOfNames, - forOfObject, - forOfObjectChecked, - keys - ], + keywords: unique( + functions.map((fn) => fn.keywords) + .reduce((keywords, fnKeywords) => [...keywords, ...fnKeywords]) + ).sort(), + functions, testDataType: 'object' }; diff --git a/lib/profiles/object-iteration/object-iteration.profile.spec.js b/lib/profiles/object-iteration/object-iteration.profile.spec.js index 0a414a3..e9a7913 100644 --- a/lib/profiles/object-iteration/object-iteration.profile.spec.js +++ b/lib/profiles/object-iteration/object-iteration.profile.spec.js @@ -29,11 +29,11 @@ describe('Object iteration', () => { result = fn.f(data[testDataType]); }); - it('should return a string', () => { + it('returns a string', () => { expect(typeof result).to.equal('string'); }); - it('should return a concatenation of the property names of the given data object', () => { + it('returns a concatenation of the property names of the given data object', () => { expect(result).to.equal('numarrstr'); }); }); diff --git a/lib/profiles/recursion/index.js b/lib/profiles/recursion/index.js index b7d0ae4..710273f 100644 --- a/lib/profiles/recursion/index.js +++ b/lib/profiles/recursion/index.js @@ -1,32 +1,36 @@ +const unique = require('../../support/array').unique; + const recursiveSum = { description: 'recursive sum', - f: (d) => { - if (d.length === 0) { - return 0; - } - - return d[0] + recursiveSum.f(d.slice(1)); - } + keywords: [ + 'recursion', + 'sum' + ].sort(), + codeSample: 'const f = (d) => (d && d.length && (d[0] + f(d.slice(1)))) || 0', + f: (d) => (d && d.length && (d[0] + recursiveSum.f(d.slice(1)))) || 0 }; const tailRecursiveSum = { description: 'tail recursive sum', - f: (d, i) => { - if (typeof i === 'undefined') { - i = 0; - } - - if (d.length === 0) { - return i; - } - - i += d[0]; - return tailRecursiveSum.f(d.slice(1), i); - } + keywords: [ + 'recursion', + 'sum', + 'tail', + 'tailrecursion' + ].sort(), + codeSample: 'const f = (d, i = 0) => (!d.length && i) || f(d.slice(1), i + d[0])', + f: (d, i = 0) => (!d.length && i) + || tailRecursiveSum.f(d.slice(1), i + d[0]) }; const forReferenceSum = { description: 'for loop sum for reference', + keywords: [ + 'for', + 'loop', + 'sum' + ].sort(), + codeSample: 'for (...) { sum += d[i] }', f: (d) => { let sum = 0; for (let i = 0; i < d.length; i++) { @@ -37,16 +41,22 @@ const forReferenceSum = { } }; +const functions = [ + forReferenceSum, + recursiveSum, + tailRecursiveSum +]; + module.exports = { name: 'recursion', description: { long: 'Recursion variations: Calculating sum of array of integers. Profile contains a simple for-loop for reference.', short: 'Recursion.' }, - functions: [ - forReferenceSum, - recursiveSum, - tailRecursiveSum - ], + keywords: unique( + functions.map((test) => test.keywords) + .reduce((keywords, testKeywords) => [...keywords, ...testKeywords]) + ).sort(), + functions, testDataType: 'array' }; diff --git a/lib/profiles/recursion/recursion.profile.spec.js b/lib/profiles/recursion/recursion.profile.spec.js index 3f4f916..26f6da1 100644 --- a/lib/profiles/recursion/recursion.profile.spec.js +++ b/lib/profiles/recursion/recursion.profile.spec.js @@ -14,12 +14,12 @@ describe('Recursion', () => { result = fn.f(data); }); - it('should return an integer', () => { + it('returns an integer', () => { expect(typeof result).to.eql('number'); expect(parseInt(result, 10)).to.eql(result); }); - it('should calculate the sum of the integers in the given array', () => { + it('calculates the sum of the integers in the given array', () => { expect(result).to.eql(15); }); }); From 59e2376cbdb536c61ecd1bdcbe5cb89a8dc5e7ea Mon Sep 17 00:00:00 2001 From: HP Dietz Date: Sun, 11 Aug 2019 22:09:31 +0200 Subject: [PATCH 4/7] Update dependencies. Output new profile properties. Replace subjunctive with assertive phrasing in unit tests. Fix outdated docs. Add new features and migration guide to readme. --- .eslintrc.json | 2 +- CHANGELOG.md | 14 ++ README.md | 183 ++++++++++++---- js-profiler.js | 50 +++-- lib/profile-runner/profile-runner.spec.js | 10 +- lib/reporter/console/index.js | 88 ++++---- lib/reporter/json/index.js | 1 - lib/reporter/reporter/index.js | 14 +- lib/support/clock/clock.spec.js | 6 +- lib/support/profiler/profiler.spec.js | 14 +- lib/support/testdata/testdata.spec.js | 2 +- package-lock.json | 252 ++++++++++++---------- package.json | 6 +- 13 files changed, 393 insertions(+), 249 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 8aa30fe..cd31336 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,7 +6,7 @@ "es6": true }, "parserOptions": { - "ecmaVersion": 6, + "ecmaVersion": 9, "sourceType": "script", "impliedStrict": false }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 004a691..6ffef26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +### 2.0.0 +* [#86: Add better descriptions to profiles and profile tests.](https://github.com/haensl/js-profiler/issues/86) +* [#69: Fix outdated docs.](https://github.com/haensl/js-profiler/issues/69) +* Rename `profile.tests` to `profile.functions`. +* Add human readable descriptions to profile functions. +* Add keywords to profile functions. +* Add codeSample to profile functions. +* Add strict vs equal comparisons to guards profile. +* Update dependencies. +* Add new features and migration guide to readme. +* Improve profile test descriptions. +* Add keywords to profiles. +* Add array support module. + ### 1.24.0 * [#83: Add Object.defineProperty to object creation profile.](https://github.com/haensl/js-profiler/issues/83) diff --git a/README.md b/README.md index 2bfd31a..7a949e9 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,54 @@ -# JS-Profiler +# [JS-Profiler](https://js-profiler.com) JavaScript profiling tool and library of profiling modules and benchmarks. -JS-Profiler allows you to compare different techniques and functions regarding execution speed and memory consumption. It reports results either in text or JSON format. +JS-Profiler allows you to compare different techniques, operators and functions regarding execution speed and memory consumption. It reports results either in text or JSON format. + +JS-Profiler is what powers [https://js-profiler.com](https://js-profiler.com). [![NPM](https://nodei.co/npm/js-profiler.png?downloads=true)](https://nodei.co/npm/js-profiler/) [![Build Status](https://travis-ci.org/haensl/js-profiler.svg?branch=master)](https://travis-ci.org/haensl/js-profiler) -## Installation - -`npm i [-g] js-profiler` - -## New in version 2 & Migration from v1.x.y to v2.x.y -* `test.description` now containsa _nice_ human readable description. -* `test.codeSample` now contains a short pseudo-code sample of the function under test. -* use `test.code` to access the full source code of the function under test. -* `test.keywords` contains keywords associated with the function under test. - -### Comparison of v2 vs. v1 profile object - -#### Version 1.x.y profile object +## Table of contents + +* [Installation](#installation) +* [New in version 2 & Migration](#new-in-v2) + * [Comparison of v1 vs. v2 profile object](#comp-v2-v1-profile) + * [v1 profile object](#v1-profile) + * [v2 profile object](#v2-profile) +* [Usage](#usage) + * [CLI](#usage-cli) + * [Library](#usage-lib) +* [Profiles](#profiles) + * [array concatenation](#array-concat) + * [comparison operators](#comparison-operators) + * [guards](#guards) + * [loops](#loops) + * [map access](#map:access) + * [map creation](#map:creation) + * [object iteration](#object-iteration) + * [recursion](#recursion) +* [Documentation](docs/index.md) +* [Changelog](CHANGELOG.md) +* [License](LICENSE) + +## Installation + +`npm i [-gS] js-profiler` + +## New in version 2 & Migration from v1.x.y to v2.x.y + +* `profile.tests` is renamed to `profile.functions` +* `function.description` _(formerly `test.description`)_ now contains a _nice_ human readable description. +* `function.codeSample` now contains a short pseudo-code sample of the function under test. +* use `function.code` to access the full source code of the function under test. +* `function.keywords` contains keywords associated with the function under test. +* `profile.keywords` contains keywords associated with this profile. + +### Comparison of a v1 vs. v2 profile object + +#### Version 1.x.y profile object ```javascript // v1 @@ -66,14 +94,22 @@ JS-Profiler allows you to compare different techniques and functions regarding e } ``` -#### Version 2.x.y profile object +#### Version 2.x.y profile object ```javascript // v2 { "name": "recursion", "description": "Recursion.", - "tests": [ + "keywords": [ + "for", + "loop", + "recursion", + "sum", + "tail", + "tailrecursion" + ], + "functions": [ { "description": "for loop sum for reference", "keywords": [ @@ -84,7 +120,7 @@ JS-Profiler allows you to compare different techniques and functions regarding e "codeSample": "for (...) { sum += d[i] }", "code": "(d) => {\n let sum = 0;\n for (let i = 0; i < d.length; i++) {\n sum += d[i];\n }\n\n return sum;\n }", "time": { - "average": "2.8409µs" + "average": "3.8774µs" } }, { @@ -96,7 +132,7 @@ JS-Profiler allows you to compare different techniques and functions regarding e "codeSample": "const f = (d) => (d && d.length && (d[0] + f(d.slice(1)))) || 0", "code": "(d) => (d && d.length && (d[0] + recursiveSum.f(d.slice(1)))) || 0", "time": { - "average": "735.3804µs" + "average": "733.7537µs" } }, { @@ -110,7 +146,7 @@ JS-Profiler allows you to compare different techniques and functions regarding e "codeSample": "const f = (d, i = 0) => (!d.length && i) || f(d.slice(1), i + d[0])", "code": "(d, i = 0) => (!d.length && i)\n || tailRecursiveSum.f(d.slice(1), i + d[0])", "time": { - "average": "683.1078µs" + "average": "769.7328µs" } } ], @@ -125,16 +161,16 @@ JS-Profiler allows you to compare different techniques and functions regarding e "codeSample": "for (...) { sum += d[i] }", "code": "(d) => {\n let sum = 0;\n for (let i = 0; i < d.length; i++) {\n sum += d[i];\n }\n\n return sum;\n }", "time": { - "average": "2.8409µs" + "average": "3.8774µs" } } ] } ``` -## Usage +## Usage -### CLI +### CLI If installed with the `-g` flag you can simply run js-profiler from your command line: @@ -142,7 +178,7 @@ If installed with the `-g` flag you can simply run js-profiler from your command For further information please refer to the [CLI documentation](docs/cli.md) and the man page. -### Library +### Library ```javascript // 1. Import the library @@ -157,25 +193,37 @@ jsProfiler.run() For configuration options please refer to the [Library documentation](docs/lib.md). -## Currently implemented performance profiles: +## Available performance profiles: -##### guards +### [guards](https://js-profiler.com/#guards) Variable guards: checking whether a variable is defined or of a certain type. -Profiled functions: - * `typeof !== undefined` - * `typeof === type` +Profiled operations: + * `typeof !== 'undefined'` + * `typeof != 'undefined'` + * `typeof === 'function'` + * `typeof == 'function'` + * `typeof === 'number'` + * `typeof == 'number'` + * `typeof === 'object'` + * `typeof == 'object'` + * `typeof === 'string'` + * `typeof == 'string'` * `Array.isArray` * `!!var` * `!var` * `isNaN(var)` + * `Number.isNaN(var)` + * `!isNaN(var)` + * `!Number.IsNaN(var)` * `prop in obj` * `obj.hasOwnProperty(prop)` + * `Object.prototype.hasOwnProperty.call(obj, prop)` -##### loops +### [loops](https://js-profiler.com/#loops) Loop variations: Converting an array of integers into an array of booleans satisfying a conjunction of two simple relational operations. -Profiled functions: +Profiled operations: * `[].forEach() => []` * `for(i++, i < d.length) => []` * `for(i++, i < len) => []` @@ -183,31 +231,80 @@ Profiled functions: * `[].map() => []` * `while(i < d.length) => []` * `while(i < len) => []` + * `do { } while (i < d.length)` + * `do { } while (i < len)` + * `for (prop of [])` -##### map:access +### [map access](https://js-profiler.com/#map:access) Object literal vs. Map: retrieving values. -Profiled functions: +Profiled operations: * `Map.get()` * `{}.prop` -##### map:creation +### [map creation](https://js-profiler.com/#map:creation) Object literal vs. Map: creating a map. -Profiled functions: +Profiled operations: * `Map.set()` - * `{}.prop =` + * `new Map([props])` + * `{}.prop = val` + * `Object.defineProperty({}, prop, desc)` + * `Object.defineProperties({}, props)` + * `{ ...props }` -##### recursion +### [recursion](https://js-profiler.com/#recursion) Recurstion variations: Calculating sum of array of integers. Profile contains a simple for-loop for reference. -Profiled functions: +Profiled operations: * `for loop sum for reference` * `recursive sum` * `tail recursive sum` -### [Documentation](docs/index.md) - -### [Changelog](CHANGELOG.md) - -### [License](LICENSE) +### [array concatenation](https://js-profiler.com/#array-concatenation) +Array concatenation variations: Combining two arrays using different techniques. + +Profiled operations: + * `a.concat(b)` + * `for (...) { a.push(b[i])}` + * `for (...) { b.unshift(a[i])}` + * `a.push.apply(a, b)` + * `b.unshift.appy(b, a)` + * `b.reduce((arr, item) => arr.push(item), a)` + * `a.reduceRight((arr, item) => arr.unshift(item), b)` + * `[...a, ...b]` + +### [comarison operators](https://js-profiler.com/#comparison-operators) +Variable comparison operators. + +Profiled operations: + * `a > b` + * `a >= b` + * `a < b` + * `a <= b` + * `==` + * `===` + * `!=` + * `!==` + * `&&` + * || + +### [object iteration](https://js-profiler.com/#object-iteration) +Object iteration: different ways of iterating over properties of an object and concatenating property names into a single string. + +Profiled operations: + * `for (const prop in obj) {}` + * `Object.keys(obj).forEach()` + * `Object.entries(obj).forEach()` + * `for (prop of Map.keys())` + * `for (prop of Object.keys(obj))` + * `for (prop of Object.keys(obj) { obj.hasOwnProperty(prop) && ... })` + * `for (prop of Object.getOwnPropertyNames(obj))` + * `Object.getOwnPropertyNames(obj).forEach()` + + +## [Documentation](docs/index.md) + +## [Changelog](CHANGELOG.md) + +## [License](LICENSE) diff --git a/js-profiler.js b/js-profiler.js index 847c07e..7b7844f 100755 --- a/js-profiler.js +++ b/js-profiler.js @@ -1,7 +1,5 @@ #!/usr/bin/env node --expose-gc -const glob = require('glob'); -const join = require('path').join; const GetOpt = require('node-getopt'); const chalk = require('chalk'); const DEFAULTS = require('./lib/support/defaults'); @@ -10,24 +8,24 @@ const UNITS = require('./lib/support/units'); const jsProfiler = require('./lib'); const opts = new GetOpt([ - ['h', 'help', 'Display this helptext.'], - ['i', 'iterations=', `Specify the number of iterations per profiled function. Default: ${DEFAULTS.iterations}.`], - ['j', 'json', `Output results in JSON format.`], - ['l', 'list', 'List available profiles.'], - ['m', 'magnitude=', `Specify the magnitude of testdata. Default: ${DEFAULTS.magnitude}.`], - ['', 'memory', 'If present, memory consumption is measured.'], - ['p', 'precision=', `Specify the precision in terms of decimal places of results. Default: ${DEFAULTS.precision.time},${DEFAULTS.precision.memory}. Separate time and memory precision by comma.`], - ['q', 'quiet', 'Print results only.'], - ['u', 'unit=', `Specify the unit for time and memory output. Default: ${DEFAULTS.units.time},${DEFAULTS.units.memory}. Possible values: auto (automatically convert between milli- and microseconds), ms (milliseconds), µs (microseconds), B (Bytes), KB (kilobytes), MB (megabytes). Separate time and memory unit by comma.`], - ['v', 'verbose', 'Print verbose information.'] - ]).setHelp( - 'Usage: js-profiler [OPTIONS] [profile1 profile2 ...]\n\n' + - 'Parameters:\n' + - ' profile1 profile2 ...\n' + - ' Optionally specify the profiles you want to run separated by spaces.\n\n' + - 'Options:\n' + - '[[OPTIONS]]\n' - ).bindHelp().parseSystem(); + ['h', 'help', 'Display this helptext.'], + ['i', 'iterations=', `Specify the number of iterations per profiled function. Default: ${DEFAULTS.iterations}.`], + ['j', 'json', 'Output results in JSON format.'], + ['l', 'list', 'List available profiles.'], + ['m', 'magnitude=', `Specify the magnitude of testdata. Default: ${DEFAULTS.magnitude}.`], + ['', 'memory', 'If present, memory consumption is measured.'], + ['p', 'precision=', `Specify the precision in terms of decimal places of results. Default: ${DEFAULTS.precision.time},${DEFAULTS.precision.memory}. Separate time and memory precision by comma.`], + ['q', 'quiet', 'Print results only.'], + ['u', 'unit=', `Specify the unit for time and memory output. Default: ${DEFAULTS.units.time},${DEFAULTS.units.memory}. Possible values: auto (automatically convert between milli- and microseconds), ms (milliseconds), µs (microseconds), B (Bytes), KB (kilobytes), MB (megabytes). Separate time and memory unit by comma.`], + ['v', 'verbose', 'Print verbose information.'] +]).setHelp( + 'Usage: js-profiler [OPTIONS] [profile1 profile2 ...]\n\n' + + 'Parameters:\n' + + ' profile1 profile2 ...\n' + + ' Optionally specify the profiles you want to run separated by spaces.\n\n' + + 'Options:\n' + + '[[OPTIONS]]\n' +).bindHelp().parseSystem(); const options = Object.assign({}, DEFAULTS, { console: true }); @@ -62,11 +60,11 @@ if ('list' in opts.options) { console.info(profileList.map((profile) => { switch (options.verbosity) { case VERBOSITY.VERBOSE: - return `${chalk.bold.underline(profile.name)}\n` + - `${profile.description.long}\n` + - `Profiled functions:\n` + - `${profile.functions.map((f) => ` ${f}`) - .join('\n')}` + return `${chalk.bold.underline(profile.name)}\n` + + `${profile.description.long}\n` + + 'Profiled functions:\n' + + `${profile.functions.map((f) => ` ${f}`) + .join('\n')}`; case VERBOSITY.NORMAL: return `${chalk.bold.underline(profile.name)}: ${profile.description.short}`; } @@ -116,7 +114,7 @@ if ('unit' in opts.options) { } else { console.warn(chalk.yellow(`WARNING: "${units[0]}" is not a valid time unit. Defaulting to ${options.units.time}.`)); } - + if (units.length > 1) { if (UNITS.isValidMemoryUnit(units[1])) { options.units.memory = units[1]; diff --git a/lib/profile-runner/profile-runner.spec.js b/lib/profile-runner/profile-runner.spec.js index c2db830..389055e 100644 --- a/lib/profile-runner/profile-runner.spec.js +++ b/lib/profile-runner/profile-runner.spec.js @@ -25,7 +25,7 @@ describe('Profile Runner', () => { profileRunner = new ProfileRunner(options); }); - it('Should create a profile runner', () => { + it('creates a profile runner', () => { expect(profileRunner).to.exist; }); @@ -34,7 +34,7 @@ describe('Profile Runner', () => { beforeEach(() => { spies = new Map(); - for (let event in events) { + for (const event in events) { const spy = sinon.spy(); profileRunner.on(events[event], spy); spies.set(events[event], spy); @@ -43,17 +43,17 @@ describe('Profile Runner', () => { profileRunner.run(); }); - for (let event in events) { + for (const event in events) { if (event === 'ERROR') { continue; } - it(`Should emit the ${event} event`, () => { + it(`emits the ${event} event`, () => { expect(spies.get(events[event])).to.have.been.called; }); } - it('Should call the profiled function for the number of iterations', () => { + it('calls the profiled function for the number of iterations', () => { expect(options.profiles[0].functions[0].f) .to.have.callCount(options.iterations); }); diff --git a/lib/reporter/console/index.js b/lib/reporter/console/index.js index dd4b212..7d45a16 100644 --- a/lib/reporter/console/index.js +++ b/lib/reporter/console/index.js @@ -3,11 +3,7 @@ const VERBOSITY = require('../../support/verbosity'); const events = require('../../support/events'); const Reporter = require('../reporter'); -class ConsoleReporter extends Reporter{ - constructor(options) { - super(options); - } - +class ConsoleReporter extends Reporter { reportOn(profileRunner) { profileRunner.on(events.START, (profiles) => { this.printOptions(); @@ -55,23 +51,23 @@ class ConsoleReporter extends Reporter{ printOptions() { if (this.options.verbosity >= VERBOSITY.NORMAL) { console.info( - `js-profiler v${this.report.jsprofiler.version}\n` + - `node v${process.versions.node}\n` + - `v8 v${process.versions.v8}` + `js-profiler v${this.report.jsprofiler.version}\n` + + `node v${process.versions.node}\n` + + `v8 v${process.versions.v8}` ); } if (this.options.verbosity === VERBOSITY.VERBOSE) { console.info( - `Magnitude: ${this.options.magnitude}\n` + - `Iterations: ${this.options.iterations}\n` + - `Enable memory measurement: ${this.options.memory ? 'yes' : 'no'}\n` + - `Units:\n` + - ` Time: ${this.options.units.time}\n` + - ` Memory: ${this.options.units.memory}\n` + - `Precision:\n` + - ` Time: ${this.options.precision.time}\n` + - ` Memory: ${this.options.precision.memory}` + `Magnitude: ${this.options.magnitude}\n` + + `Iterations: ${this.options.iterations}\n` + + `Enable memory measurement: ${this.options.memory ? 'yes' : 'no'}\n` + + 'Units:\n' + + ` Time: ${this.options.units.time}\n` + + ` Memory: ${this.options.units.memory}\n` + + 'Precision:\n' + + ` Time: ${this.options.precision.time}\n` + + ` Memory: ${this.options.precision.memory}` ); } } @@ -85,32 +81,32 @@ class ConsoleReporter extends Reporter{ case VERBOSITY.NORMAL: if (this.memory) { console.info( - ` avg: ${formattedTestResult.time.average} |` + - `${formattedTestResult.memory.average}\n` + ` avg: ${formattedTestResult.time.average} |` + + `${formattedTestResult.memory.average}\n` ); } else { console.info(` avg: ${formattedTestResult.time.average}`); } break; - case VERBOSITY.VERBOSE: + case VERBOSITY.VERBOSE: + console.info( + ' time:\n' + + ` avg: ${formattedTestResult.time.average}\n` + + ` min: ${formattedTestResult.time.minimum}\n` + + ` max: ${formattedTestResult.time.maximum}` + ); + if (this.memory) { console.info( - ` time:\n` + - ` avg: ${formattedTestResult.time.average}\n` + - ` min: ${formattedTestResult.time.minimum}\n` + - ` max: ${formattedTestResult.time.maximum}` + ' memory:\n' + + ` avg: ${formattedTestResult.memory.average}\n` + + ` min: ${formattedTestResult.memory.minimum}\n` + + ` max: ${formattedTestResult.memory.maximum}` ); - if (this.memory) { - console.info( - ` memory:\n` + - ` avg: ${formattedTestResult.memory.average}\n` + - ` min: ${formattedTestResult.memory.minimum}\n` + - ` max: ${formattedTestResult.memory.maximum}` - ); - } + } - break; - } + break; + } } /** @@ -119,24 +115,28 @@ class ConsoleReporter extends Reporter{ * print */ printProfileResult(formattedProfileResult) { - if (this.options.verbosity >= VERBOSITY.NORMAL) { - console.info('\n =============='); - console.info(chalk.green( - ` Fastest:\n` + + if (this.options.verbosity >= VERBOSITY.NORMAL) { + console.info('\n =============='); + console.info(chalk.green( + ' Fastest:\n' + + `${ formattedProfileResult.fastest.map((f) => ` ${f.description} avg: ${f.time.average}` ).join('\n') - )); + }` + )); - if (this.memory) { - console.info(chalk.green( - ` Lowest memory consumption:\n` + + if (this.memory) { + console.info(chalk.green( + ' Lowest memory consumption:\n' + + `${ formattedProfileResult.lowestMemory.map((m) => ` ${m.description} avg: ${m.memory.average}` ).join('\n') - )); - } + }` + )); } + } } } diff --git a/lib/reporter/json/index.js b/lib/reporter/json/index.js index e8767a3..63307cc 100644 --- a/lib/reporter/json/index.js +++ b/lib/reporter/json/index.js @@ -1,4 +1,3 @@ -const events = require('../../support/events'); const Reporter = require('../reporter'); class JSONReporter extends Reporter { diff --git a/lib/reporter/reporter/index.js b/lib/reporter/reporter/index.js index b8a52da..24a3c63 100644 --- a/lib/reporter/reporter/index.js +++ b/lib/reporter/reporter/index.js @@ -13,7 +13,7 @@ class Reporter { this.options = options; this.report = { jsprofiler: { - version: jsProfilerVersion, + version: jsProfilerVersion }, node: { version: process.versions.node @@ -43,7 +43,6 @@ class Reporter { .filter((a, i, arr) => a.time.average === arr[0].time.average); } - /** * Extracts the test results with lowest memory consumption * @param {object} results of profile run @@ -59,7 +58,6 @@ class Reporter { .filter((a, i, arr) => a.memory.average === arr[0].memory.average); } - /** * @param {ProfileRunner} profileRunner The test runner */ @@ -69,7 +67,7 @@ class Reporter { reject(err); }); - profileRunner.on(events.END, (profiles) => { + profileRunner.on(events.END, () => { resolve(this.report); }); @@ -98,7 +96,8 @@ class Reporter { if (this.options.verbosity >= VERBOSITY.NORMAL) { p.name = profile.name, p.description = profile.description.short; - p.tests = this.profiles[profile.name]; + p.keywords = profile.keywords; + p.functions = this.profiles[profile.name]; p.fastest = this.formatFastest(result.testResults); const lowestMemory = this.formatLowestMemory(result.testResults); @@ -108,7 +107,7 @@ class Reporter { } if (this.options.verbosity === VERBOSITY.VERBOSE) { - p.description = profile.description.long; + p.description = profile.description.long; } return p; @@ -144,6 +143,9 @@ class Reporter { formatTestResult(testResult) { const r = { description: testResult.func.description, + keywords: testResult.func.keywords, + codeSample: testResult.func.codeSample, + code: `${testResult.func.f}`, time: { average: this.formatMicros(testResult.time.average) } diff --git a/lib/support/clock/clock.spec.js b/lib/support/clock/clock.spec.js index a7d5eda..f2339e5 100644 --- a/lib/support/clock/clock.spec.js +++ b/lib/support/clock/clock.spec.js @@ -15,11 +15,11 @@ describe('Clock', () => { t = clock.time(fn); }); - it('should execute the function', () => { + it('executes the function', () => { expect(fn.called).to.be.true; }); - it('should return the time it took to execute the function in high resolution format', () => { + it('returns the time it took to execute the function in high resolution format', () => { expect(Array.isArray(t)).to.be.true; t.forEach((item) => { expect(typeof item).to.eql('number'); @@ -27,7 +27,7 @@ describe('Clock', () => { }); describe('and not supplying a function', () => { - it('should throw an exception', () => { + it('throws an exception', () => { expect(clock.time).to.throw(Error); }); }); diff --git a/lib/support/profiler/profiler.spec.js b/lib/support/profiler/profiler.spec.js index 34f17a8..61361d7 100644 --- a/lib/support/profiler/profiler.spec.js +++ b/lib/support/profiler/profiler.spec.js @@ -19,11 +19,11 @@ describe('Profiler', () => { }); }); - it('should return an object', () => { + it('returns an object', () => { expect(typeof profile).to.eql('object'); }); - it('should return the time it took to execute the function', () => { + it('returns the time it took to execute the function', () => { expect(Array.isArray(profile.time)).to.be.true; }); }); @@ -45,7 +45,7 @@ describe('Profiler', () => { global.gc = gcBak; }); - it('should throw an exception', () => { + it('throws an exception', () => { expect(p).to.throw(Error); }); }); @@ -63,19 +63,19 @@ describe('Profiler', () => { global.gc.reset(); }); - it('should call the garbage collector', () => { + it('calls the garbage collector', () => { expect(global.gc.called).to.be.true; }); - it('should return an object', () => { + it('returns an object', () => { expect(typeof profile).to.eql('object'); }); - it('should return the time it took to execute the function', () => { + it('returns the time it took to execute the function', () => { expect(Array.isArray(profile.time)).to.be.true; }); - it ('should return the heap space consumed when executing the function', () => { + it('returns the heap space consumed when executing the function', () => { expect(typeof profile.heap).to.eql('number'); }); }); diff --git a/lib/support/testdata/testdata.spec.js b/lib/support/testdata/testdata.spec.js index 7c8ca94..026a6a1 100644 --- a/lib/support/testdata/testdata.spec.js +++ b/lib/support/testdata/testdata.spec.js @@ -139,7 +139,7 @@ describe('testdata', () => { }); it('generates an array of arrays', () => { - for (let e of data) { + for (const e of data) { expect(Array.isArray(e)).to.be.true; } }); diff --git a/package-lock.json b/package-lock.json index ee8ed3b..06fda9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "js-profiler", - "version": "1.22.0", + "version": "1.24.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -52,9 +52,9 @@ "dev": true }, "ansi-escapes": { - "version": "3.1.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "ansi-regex": { @@ -119,12 +119,6 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", @@ -187,9 +181,9 @@ "dev": true }, "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "dev": true }, "circular-json": { @@ -264,15 +258,27 @@ "dev": true }, "cosmiconfig": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz", - "integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "dev": true, "requires": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", - "js-yaml": "^3.9.0", + "js-yaml": "^3.13.1", "parse-json": "^4.0.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } } }, "cross-spawn": { @@ -298,9 +304,9 @@ }, "dependencies": { "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } @@ -368,7 +374,7 @@ }, "eslint": { "version": "4.19.1", - "resolved": "http://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", "dev": true, "requires": { @@ -428,9 +434,9 @@ } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -487,7 +493,7 @@ }, "espree": { "version": "3.5.4", - "resolved": "http://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "dev": true, "requires": { @@ -526,9 +532,9 @@ "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "execa": { @@ -548,7 +554,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { @@ -559,7 +565,7 @@ }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", "dev": true }, @@ -651,9 +657,9 @@ } }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -664,15 +670,15 @@ } }, "globals": { - "version": "11.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", - "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.1.tgz", + "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==", "dev": true }, "growl": { @@ -702,22 +708,36 @@ "dev": true }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.2.tgz", + "integrity": "sha512-CyjlXII6LMsPMyUzxpTt8fzh5QwzGqPmQXgY/Jyf4Zfp27t/FvfhwoE/8laaMUcMy816CkWF20I7NeQhwwY88w==", + "dev": true, + "requires": { + "lru-cache": "^5.1.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + } + } }, "husky": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-1.2.0.tgz", - "integrity": "sha512-/ib3+iycykXC0tYIxsyqierikVa9DA2DrT32UEirqNEFVqOj1bFMTgP3jAz8HM7FgC/C8pc/BTUa9MV2GEkZaA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/husky/-/husky-1.3.1.tgz", + "integrity": "sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==", "dev": true, "requires": { - "cosmiconfig": "^5.0.6", + "cosmiconfig": "^5.0.7", "execa": "^1.0.0", "find-up": "^3.0.0", "get-stdin": "^6.0.0", - "is-ci": "^1.2.1", + "is-ci": "^2.0.0", "pkg-dir": "^3.0.0", "please-upgrade-node": "^3.1.1", "read-pkg": "^4.0.1", @@ -825,9 +845,9 @@ } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -861,22 +881,13 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "dev": true, "requires": { - "ci-info": "^1.5.0" + "ci-info": "^2.0.0" } }, "is-directory": { @@ -928,9 +939,9 @@ "dev": true }, "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -976,9 +987,9 @@ } }, "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "lolex": { @@ -988,13 +999,21 @@ "dev": true }, "lru-cache": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.4.tgz", - "integrity": "sha512-EPstzZ23znHUVLKj+lcXO1KvZkrlw+ZirdwvOmnAnA/1PB4ggyXJ77LRkCqkff+ShQ+cqoxCxLQOh4cKITO5iA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { "pseudomap": "^1.0.2", - "yallist": "^3.0.2" + "yallist": "^2.1.2" + }, + "dependencies": { + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } } }, "mimic-fn": { @@ -1109,13 +1128,13 @@ "integrity": "sha512-06LC4wHO+nyH0J07dUzFsZTVZMsMMKTkXo8BUTmuYbJhbsKX2cVDn2xADoFqjbnBYThVlGSlaM10CDyEi+48Iw==" }, "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", + "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } @@ -1168,7 +1187,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, @@ -1179,9 +1198,9 @@ "dev": true }, "p-limit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", - "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1197,9 +1216,9 @@ } }, "p-try": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", - "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "parse-json": { @@ -1235,6 +1254,12 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -1251,9 +1276,9 @@ } }, "please-upgrade-node": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", - "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", "dev": true, "requires": { "semver-compare": "^1.0.0" @@ -1272,15 +1297,15 @@ "dev": true }, "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, "progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "pseudomap": { @@ -1312,7 +1337,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -1327,7 +1352,7 @@ }, "regexpp": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", "dev": true }, @@ -1341,6 +1366,15 @@ "resolve-from": "^1.0.0" } }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, "resolve-from": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", @@ -1358,12 +1392,12 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "run-async": { @@ -1481,9 +1515,9 @@ } }, "spdx-correct": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", - "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -1507,9 +1541,9 @@ } }, "spdx-license-ids": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", - "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "sprintf-js": { @@ -1603,9 +1637,9 @@ } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", diff --git a/package.json b/package.json index 7f05bc2..ab6b5ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "js-profiler", - "version": "1.24.0", + "version": "2.0.0", "description": "Javascript profiling tool and collection of performance profiles for various JavaScript built-ins.", "main": "./lib/index.js", "man": "./docs/js-profiler.1.gz", @@ -41,14 +41,14 @@ "license": "MIT", "dependencies": { "chalk": "^1.1.3", - "glob": "^7.1.3", + "glob": "^7.1.4", "node-getopt": "^0.2.4" }, "devDependencies": { "@haensl/eslint-config": "^1.3.0", "chai": "^3.5.0", "eslint": "^4.19.1", - "husky": "^1.2.0", + "husky": "^1.3.1", "mocha": "^5.2.0", "sinon": "^1.17.7", "sinon-chai": "^2.14.0" From a49eeb51364a76c3f8c37fde33a2e906ab3c5f30 Mon Sep 17 00:00:00 2001 From: HP Dietz Date: Sun, 11 Aug 2019 22:11:20 +0200 Subject: [PATCH 5/7] Phrasing. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a949e9..136714d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ JavaScript profiling tool and library of profiling modules and benchmarks. JS-Profiler allows you to compare different techniques, operators and functions regarding execution speed and memory consumption. It reports results either in text or JSON format. -JS-Profiler is what powers [https://js-profiler.com](https://js-profiler.com). +JS-Profiler powers [https://js-profiler.com](https://js-profiler.com). [![NPM](https://nodei.co/npm/js-profiler.png?downloads=true)](https://nodei.co/npm/js-profiler/) From c71307df85fe9dc4f5aa877cfd1896cfcf8ffebd Mon Sep 17 00:00:00 2001 From: HP Dietz Date: Sun, 11 Aug 2019 22:17:28 +0200 Subject: [PATCH 6/7] Add JS-Profiler logo. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 136714d..6a6773e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # [JS-Profiler](https://js-profiler.com) +[https://js-profiler.com](https:/js-profiler.com) + JavaScript profiling tool and library of profiling modules and benchmarks. JS-Profiler allows you to compare different techniques, operators and functions regarding execution speed and memory consumption. It reports results either in text or JSON format. From bf8a730f00aad3db5b4052d3a2be6d678c079569 Mon Sep 17 00:00:00 2001 From: HP Dietz Date: Sun, 11 Aug 2019 22:21:51 +0200 Subject: [PATCH 7/7] Migrate to new husky config format. --- package.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ab6b5ae..848f4e8 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,13 @@ "start": "node js-profiler.js", "test": "mocha --recursive \"./{,!(node_modules)/**/}*.spec.js\"", "tdd": "mocha --recursive --watch \"./{,!(node_modules)/**/}*.spec.js\"", - "lint": "eslint -c ./.eslintrc.json **/*.js", - "precommit": "npm run lint && npm test", - "prepush": "npm run lint && npm test" + "lint": "eslint -c ./.eslintrc.json **/*.js" + }, + "husky": { + "hooks": { + "pre-commit": "npm run lint && npm test", + "pre-push": "npm run lint && npm test" + } }, "keywords": [ "Performance",