diff --git a/.babelrc b/.babelrc index 5398794d..6bb363b5 100644 --- a/.babelrc +++ b/.babelrc @@ -5,7 +5,7 @@ { "useBuiltIns": true, "targets": { - "node": 4.3 + "node": "4.3" }, "exclude": [ "transform-async-to-generator", diff --git a/.eslintignore b/.eslintignore index f972a0c4..70cc4d0d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,6 @@ +*.snap /node_modules /dist /examples/build +/coverage/ +/__tests__/stubs diff --git a/__tests__/.eslintrc b/__tests__/.eslintrc new file mode 100644 index 00000000..24082e45 --- /dev/null +++ b/__tests__/.eslintrc @@ -0,0 +1,8 @@ +{ + "plugins": [ + "jest" + ], + "env": { + "jest/globals": true + } +} diff --git a/__tests__/UglifyJsPlugin.test.js b/__tests__/UglifyJsPlugin.test.js new file mode 100644 index 00000000..75d6a527 --- /dev/null +++ b/__tests__/UglifyJsPlugin.test.js @@ -0,0 +1,7 @@ +import UglifyJsPlugin from '../src/index'; + +describe('UglifyJsPlugin', () => { + it('has apply function', () => { + expect(typeof new UglifyJsPlugin().apply).toBe('function'); + }); +}); diff --git a/__tests__/__snapshots__/all-options.test.js.snap b/__tests__/__snapshots__/all-options.test.js.snap new file mode 100644 index 00000000..8739a402 --- /dev/null +++ b/__tests__/__snapshots__/all-options.test.js.snap @@ -0,0 +1,86 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`errors 1`] = `Array []`; + +exports[`main.js 1`] = ` +"webpackJsonp([ 0 ], [ function(module, exports) { + module.exports = function() { + console.log(7); + }; +} ], [ 0 ]);" +`; + +exports[`manifest.js 1`] = ` +"!function(modules) { + function __webpack_require__(moduleId) { + if (installedModules[moduleId]) return installedModules[moduleId].exports; + var module = installedModules[moduleId] = { + i: moduleId, + l: !1, + exports: {} + }; + return modules[moduleId].call(module.exports, module, module.exports, __webpack_require__), + module.l = !0, module.exports; + } + var parentJsonpFunction = window.webpackJsonp; + window.webpackJsonp = function(chunkIds, moreModules, executeModules) { + for (var moduleId, chunkId, result, i = 0, resolves = []; i < chunkIds.length; i++) chunkId = chunkIds[i], + installedChunks[chunkId] && resolves.push(installedChunks[chunkId][0]), installedChunks[chunkId] = 0; + for (moduleId in moreModules) Object.prototype.hasOwnProperty.call(moreModules, moduleId) && (modules[moduleId] = moreModules[moduleId]); + for (parentJsonpFunction && parentJsonpFunction(chunkIds, moreModules, executeModules); resolves.length; ) resolves.shift()(); + if (executeModules) for (i = 0; i < executeModules.length; i++) result = __webpack_require__(__webpack_require__.s = executeModules[i]); + return result; + }; + var installedModules = {}, installedChunks = { + 1: 0 + }; + __webpack_require__.e = function(chunkId) { + function onScriptComplete() { + script.onerror = script.onload = null, clearTimeout(timeout); + var chunk = installedChunks[chunkId]; + 0 !== chunk && (chunk && chunk[1](new Error(\\"Loading chunk \\" + chunkId + \\" failed.\\")), + installedChunks[chunkId] = void 0); + } + var installedChunkData = installedChunks[chunkId]; + if (0 === installedChunkData) return new Promise(function(resolve) { + resolve(); + }); + if (installedChunkData) return installedChunkData[2]; + var promise = new Promise(function(resolve, reject) { + installedChunkData = installedChunks[chunkId] = [ resolve, reject ]; + }); + installedChunkData[2] = promise; + var head = document.getElementsByTagName(\\"head\\")[0], script = document.createElement(\\"script\\"); + script.type = \\"text/javascript\\", script.charset = \\"utf-8\\", script.async = !0, script.timeout = 12e4, + __webpack_require__.nc && script.setAttribute(\\"nonce\\", __webpack_require__.nc), + script.src = __webpack_require__.p + \\"\\" + chunkId + \\".js\\"; + var timeout = setTimeout(onScriptComplete, 12e4); + return script.onerror = script.onload = onScriptComplete, head.appendChild(script), + promise; + }, __webpack_require__.m = modules, __webpack_require__.c = installedModules, __webpack_require__.d = function(exports, name, getter) { + __webpack_require__.o(exports, name) || Object.defineProperty(exports, name, { + configurable: !1, + enumerable: !0, + get: getter + }); + }, __webpack_require__.n = function(module) { + var getter = module && module.__esModule ? function() { + return module.default; + } : function() { + return module; + }; + return __webpack_require__.d(getter, \\"a\\", getter), getter; + }, __webpack_require__.o = function(object, property) { + return Object.prototype.hasOwnProperty.call(object, property); + }, __webpack_require__.p = \\"\\", __webpack_require__.oe = function(err) { + throw console.error(err), err; + }; +}([]);" +`; + +exports[`warnings 1`] = ` +Array [ + "Error: main.js from UglifyJs +Dropping unused variable a [./__tests__/stubs/entry.js:4,0]", +] +`; diff --git a/__tests__/__snapshots__/empty-options.test.js.snap b/__tests__/__snapshots__/empty-options.test.js.snap new file mode 100644 index 00000000..c543bed2 --- /dev/null +++ b/__tests__/__snapshots__/empty-options.test.js.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`errors 1`] = `Array []`; + +exports[`main.js 1`] = `"webpackJsonp([0],[function(o,n){o.exports=function(){console.log(7)}}],[0]);"`; + +exports[`manifest.js 1`] = `"!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,u){for(var i,a,f,l=0,s=[];l:86:23 + src/index.js:243:82 + native + src/index.js:53:25 + node_modules/tapable/lib/Tapable.js:142:13 + node_modules/webpack/lib/Compilation.js:641:10 + node_modules/tapable/lib/Tapable.js:131:46 + node_modules/webpack/lib/Compilation.js:637:9 + node_modules/tapable/lib/Tapable.js:131:46 + node_modules/webpack/lib/Compilation.js:580:8", + "Error: manifest.js from UglifyJs +DefaultsError: \`invalid-option\` is not a supported option + node_modules/uglify-js/tools/node.js:27:1, :86:23 + src/index.js:243:82 + native + src/index.js:53:25 + node_modules/tapable/lib/Tapable.js:142:13 + node_modules/webpack/lib/Compilation.js:641:10 + node_modules/tapable/lib/Tapable.js:131:46 + node_modules/webpack/lib/Compilation.js:637:9 + node_modules/tapable/lib/Tapable.js:131:46 + node_modules/webpack/lib/Compilation.js:580:8", +] +`; + +exports[`main.js 1`] = ` +"webpackJsonp([0],[ +/* 0 */ +/***/ (function(module, exports) { + +// foo +/*@preserve*/ +// bar +var a = 2 + 2; + +module.exports = function Foo() { + var b = 2 + 2; + console.log(b + 1 + 2); +}; + + +/***/ }) +],[0]);" +`; + +exports[`manifest.js 1`] = ` +"/******/ (function(modules) { // webpackBootstrap +/******/ // install a JSONP callback for chunk loading +/******/ var parentJsonpFunction = window[\\"webpackJsonp\\"]; +/******/ window[\\"webpackJsonp\\"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) { +/******/ // add \\"moreModules\\" to the modules object, +/******/ // then flag all \\"chunkIds\\" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0, resolves = [], result; +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(installedChunks[chunkId]) { +/******/ resolves.push(installedChunks[chunkId][0]); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ for(moduleId in moreModules) { +/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { +/******/ modules[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(parentJsonpFunction) parentJsonpFunction(chunkIds, moreModules, executeModules); +/******/ while(resolves.length) { +/******/ resolves.shift()(); +/******/ } +/******/ if(executeModules) { +/******/ for(i=0; i < executeModules.length; i++) { +/******/ result = __webpack_require__(__webpack_require__.s = executeModules[i]); +/******/ } +/******/ } +/******/ return result; +/******/ }; +/******/ +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // objects to store loaded and loading chunks +/******/ var installedChunks = { +/******/ 1: 0 +/******/ }; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ // This file contains only the entry chunk. +/******/ // The chunk loading function for additional chunks +/******/ __webpack_require__.e = function requireEnsure(chunkId) { +/******/ var installedChunkData = installedChunks[chunkId]; +/******/ if(installedChunkData === 0) { +/******/ return new Promise(function(resolve) { resolve(); }); +/******/ } +/******/ +/******/ // a Promise means \\"currently loading\\". +/******/ if(installedChunkData) { +/******/ return installedChunkData[2]; +/******/ } +/******/ +/******/ // setup Promise in chunk cache +/******/ var promise = new Promise(function(resolve, reject) { +/******/ installedChunkData = installedChunks[chunkId] = [resolve, reject]; +/******/ }); +/******/ installedChunkData[2] = promise; +/******/ +/******/ // start chunk loading +/******/ var head = document.getElementsByTagName('head')[0]; +/******/ var script = document.createElement('script'); +/******/ script.type = 'text/javascript'; +/******/ script.charset = 'utf-8'; +/******/ script.async = true; +/******/ script.timeout = 120000; +/******/ +/******/ if (__webpack_require__.nc) { +/******/ script.setAttribute(\\"nonce\\", __webpack_require__.nc); +/******/ } +/******/ script.src = __webpack_require__.p + \\"\\" + chunkId + \\".js\\"; +/******/ var timeout = setTimeout(onScriptComplete, 120000); +/******/ script.onerror = script.onload = onScriptComplete; +/******/ function onScriptComplete() { +/******/ // avoid mem leaks in IE. +/******/ script.onerror = script.onload = null; +/******/ clearTimeout(timeout); +/******/ var chunk = installedChunks[chunkId]; +/******/ if(chunk !== 0) { +/******/ if(chunk) { +/******/ chunk[1](new Error('Loading chunk ' + chunkId + ' failed.')); +/******/ } +/******/ installedChunks[chunkId] = undefined; +/******/ } +/******/ }; +/******/ head.appendChild(script); +/******/ +/******/ return promise; +/******/ }; +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = \\"\\"; +/******/ +/******/ // on error function for async loading +/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; }; +/******/ }) +/************************************************************************/ +/******/ ([]);" +`; + +exports[`warnings 1`] = `Array []`; diff --git a/__tests__/all-options.test.js b/__tests__/all-options.test.js new file mode 100644 index 00000000..13a79a2c --- /dev/null +++ b/__tests__/all-options.test.js @@ -0,0 +1,385 @@ +import { SourceMapSource } from 'webpack-sources'; +import UglifyJsPlugin from '../src/index'; +import { + PluginEnvironment, + cleanErrorStack, + createCompiler, + compile, +} from './helpers'; + +describe('when applied with all options', () => { + let eventBindings; + let eventBinding; + + beforeEach(() => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin({ + sourceMap: true, + compress: { + warnings: true, + }, + mangle: false, + beautify: true, + comments: false, + extractComments: { + condition: 'should be extracted', + filename(file) { + return file.replace(/(\.\w+)$/, '.license$1'); + }, + banner(licenseFile) { + return `License information can be found in ${licenseFile}`; + }, + }, + }); + plugin.apply(compilerEnv); + eventBindings = pluginEnvironment.getEventBindings(); + }); + + it('matches snapshot', () => { + const compiler = createCompiler(); + new UglifyJsPlugin({ + sourceMap: true, + compress: { + warnings: true, + }, + mangle: false, + beautify: true, + comments: false, + extractComments: { + condition: 'should be extracted', + filename(file) { + return file.replace(/(\.\w+)$/, '.license$1'); + }, + banner(licenseFile) { + return `License information can be found in ${licenseFile}`; + }, + }, + }).apply(compiler); + + return compile(compiler).then((stats) => { + const errors = stats.compilation.errors.map(cleanErrorStack); + const warnings = stats.compilation.warnings.map(cleanErrorStack); + + expect(errors).toMatchSnapshot('errors'); + expect(warnings).toMatchSnapshot('warnings'); + + for (const file in stats.compilation.assets) { + if (Object.prototype.hasOwnProperty.call(stats.compilation.assets, file)) { + expect(stats.compilation.assets[file].source()).toMatchSnapshot(file); + } + } + }); + }); + + it('binds one event handler', () => { + expect(eventBindings.length).toBe(1); + }); + + describe('compilation handler', () => { + beforeEach(() => { + [eventBinding] = eventBindings; + }); + + it('binds to compilation event', () => { + expect(eventBinding.name).toBe('compilation'); + }); + + describe('when called', () => { + let chunkPluginEnvironment; + let compilationEventBindings; + let compilationEventBinding; + let compilation; + + beforeEach(() => { + chunkPluginEnvironment = new PluginEnvironment(); + compilation = chunkPluginEnvironment.getEnvironmentStub(); + compilation.assets = { + 'test.js': { + source: () => '/** @preserve Foo Bar */ function foo(longVariableName) { longVariableName = 1; }', + map: () => { + return { + version: 3, + sources: ['test.js'], + names: ['foo', 'longVariableName'], + mappings: 'AAAA,QAASA,KAAIC,kBACTA,iBAAmB', + }; + }, + }, + 'test1.js': { + source: () => 'invalid javascript', + map: () => { + return { + version: 3, + sources: ['test1.js'], + names: [''], + mappings: 'AAAA', + }; + }, + }, + 'test2.js': { + source: () => 'function foo(x) { if (x) { return bar(); not_called1(); } }', + map: () => { + return { + version: 3, + sources: ['test1.js'], + names: ['foo', 'x', 'bar', 'not_called1'], + mappings: 'AAAA,QAASA,KAAIC,GACT,GAAIA,EAAG,CACH,MAAOC,MACPC', + }; + }, + }, + 'test3.js': { + sourceAndMap: () => { + return { + source: '/** @preserve Foo Bar */ function foo(longVariableName) { longVariableName = 1; }', + map: { + version: 3, + sources: ['test.js'], + names: ['foo', 'longVariableName'], + mappings: 'AAAA,QAASA,KAAIC,kBACTA,iBAAmB', + }, + }; + }, + }, + 'test4.js': { + source: () => '/*! this comment should be extracted */ function foo(longVariableName) { /* this will not be extracted */ longVariableName = 1; } // another comment that should be extracted to a separate file\n function foo2(bar) { return bar; }', + map: () => { + return { + version: 3, + sources: ['test.js'], + names: ['foo', 'longVariableName'], + mappings: 'AAAA,QAASA,KAAIC,kBACTA,iBAAmB', + }; + }, + }, + }; + compilation.errors = []; + compilation.warnings = []; + + eventBinding.handler(compilation); + compilationEventBindings = chunkPluginEnvironment.getEventBindings(); + }); + + it('binds two event handler', () => { + expect(compilationEventBindings.length).toBe(2); + }); + + describe('build-module handler', () => { + beforeEach(() => { + [compilationEventBinding] = compilationEventBindings; + }); + + it('binds to build-module event', () => { + expect(compilationEventBinding.name).toBe('build-module'); + }); + + it('sets the useSourceMap flag', () => { + const obj = {}; + compilationEventBinding.handler(obj); + expect(obj.useSourceMap).toBeTruthy(); + }); + }); + + describe('optimize-chunk-assets handler', () => { + beforeEach(() => { + [compilationEventBinding] = compilationEventBindings; + }); + + it('binds to optimize-chunk-assets event', () => { + expect(compilationEventBindings[1].name).toBe('optimize-chunk-assets'); + }); + + it('outputs no errors for valid javascript', () => { + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + expect(compilation.errors.length).toBe(0); + }); + }); + + it('outputs SourceMapSource for valid javascript', () => { + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + expect(compilation.assets['test.js']).toBeInstanceOf(SourceMapSource); + }); + }); + + it('does not output mangled javascript', () => { + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + // eslint-disable-next-line no-underscore-dangle + expect(compilation.assets['test.js']._value).toEqual(expect.stringContaining('longVariableName')); + }); + }); + + it('outputs beautified javascript', () => { + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + // eslint-disable-next-line no-underscore-dangle + expect(compilation.assets['test.js']._value).toEqual(expect.stringContaining('\n')); + }); + }); + + it('does not preserve comments', () => { + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + // eslint-disable-next-line no-underscore-dangle + expect(compilation.assets['test.js']._value).not.toBe(expect.stringContaining('/**')); + }); + }); + + it('outputs parsing errors', () => { + compilationEventBinding.handler([{ + files: ['test1.js'], + }], () => { + expect(compilation.errors.length).toBe(1); + expect(compilation.errors[0]).toBeInstanceOf(Error); + expect(compilation.errors[0].message).toEqual(expect.stringContaining('[test1.js:1,0][test1.js:1,8]')); + }); + }); + + it('outputs warnings for unreachable code', () => { + compilationEventBinding.handler([{ + files: ['test2.js'], + }], () => { + expect(compilation.warnings.length).toBe(1); + expect(compilation.warnings[0]).toBeInstanceOf(Error); + expect(compilation.warnings[0].message).toEqual(expect.stringContaining('Dropping unreachable code')); + }); + }); + + it('works with sourceAndMap assets as well', () => { + compilationEventBinding.handler([{ + files: ['test3.js'], + }], () => { + expect(compilation.errors.length).toBe(0); + expect(compilation.assets['test3.js']).toBeInstanceOf(SourceMapSource); + }); + }); + + describe('with warningsFilter set', () => { + describe('and the filter returns true', () => { + beforeEach(() => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin({ + warningsFilter: () => true, + sourceMap: true, + compress: { + warnings: true, + }, + mangle: false, + beautify: true, + comments: false, + }); + plugin.apply(compilerEnv); + eventBindings = pluginEnvironment.getEventBindings(); + + chunkPluginEnvironment = new PluginEnvironment(); + compilation = chunkPluginEnvironment.getEnvironmentStub(); + compilation.assets = { + 'test2.js': { + source: () => 'function foo(x) { if (x) { return bar(); not_called1(); } }', + map: () => { + return { + version: 3, + sources: ['test1.js'], + names: ['foo', 'x', 'bar', 'not_called1'], + mappings: 'AAAA,QAASA,KAAIC,GACT,GAAIA,EAAG,CACH,MAAOC,MACPC', + }; + }, + }, + }; + compilation.errors = []; + compilation.warnings = []; + + eventBindings[0].handler(compilation); + compilationEventBindings = chunkPluginEnvironment.getEventBindings(); + }); + + it('should get all warnings', () => { + compilationEventBindings[1].handler([{ + files: ['test2.js'], + }], () => { + expect(compilation.warnings.length).toBe(1); + expect(compilation.warnings[0]).toBeInstanceOf(Error); + expect(compilation.warnings[0].message).toEqual(expect.stringContaining('Dropping unreachable code')); + }); + }); + }); + + describe('and the filter returns false', () => { + beforeEach(() => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin({ + warningsFilter: () => false, + sourceMap: true, + compressor: { + warnings: true, + }, + mangle: false, + beautify: true, + comments: false, + }); + plugin.apply(compilerEnv); + eventBindings = pluginEnvironment.getEventBindings(); + + chunkPluginEnvironment = new PluginEnvironment(); + compilation = chunkPluginEnvironment.getEnvironmentStub(); + compilation.assets = { + 'test2.js': { + source: () => 'function foo(x) { if (x) { return bar(); not_called1(); } }', + map: () => { + return { + version: 3, + sources: ['test1.js'], + names: ['foo', 'x', 'bar', 'not_called1'], + mappings: 'AAAA,QAASA,KAAIC,GACT,GAAIA,EAAG,CACH,MAAOC,MACPC', + }; + }, + }, + }; + compilation.errors = []; + compilation.warnings = []; + + eventBindings[0].handler(compilation); + compilationEventBindings = chunkPluginEnvironment.getEventBindings(); + }); + + it('should get no warnings', () => { + compilationEventBindings[1].handler([{ + files: ['test2.js'], + }], () => { + expect(compilation.warnings.length).toBe(0); + }); + }); + }); + }); + + it('extracts license information to separate file', () => { + compilationEventBinding.handler([{ + files: ['test4.js'], + }], () => { + expect(compilation.errors.length).toBe(0); + /* eslint-disable no-underscore-dangle */ + expect(compilation.assets['test4.license.js']._value).toEqual(expect.stringContaining('/*! this comment should be extracted */')); + expect(compilation.assets['test4.license.js']._value).toEqual(expect.stringContaining('// another comment that should be extracted to a separate file')); + expect(compilation.assets['test4.license.js']._value).not.toEqual(expect.stringContaining('/* this will not be extracted */')); + /* eslint-enable no-underscore-dangle */ + }); + }); + }); + }); + }); +}); diff --git a/__tests__/empty-options.test.js b/__tests__/empty-options.test.js new file mode 100644 index 00000000..44f7e363 --- /dev/null +++ b/__tests__/empty-options.test.js @@ -0,0 +1,185 @@ +import { RawSource } from 'webpack-sources'; +import UglifyJsPlugin from '../src/index'; +import { + PluginEnvironment, + cleanErrorStack, + createCompiler, + compile, +} from './helpers'; + +describe('when applied with no options', () => { + let eventBindings; + let eventBinding; + + beforeEach(() => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin(); + plugin.apply(compilerEnv); + eventBindings = pluginEnvironment.getEventBindings(); + }); + + it('matches snapshot', () => { + const compiler = createCompiler(); + new UglifyJsPlugin().apply(compiler); + + + return compile(compiler).then((stats) => { + const errors = stats.compilation.errors.map(cleanErrorStack); + const warnings = stats.compilation.warnings.map(cleanErrorStack); + + expect(errors).toMatchSnapshot('errors'); + expect(warnings).toMatchSnapshot('warnings'); + + for (const file in stats.compilation.assets) { + if (Object.prototype.hasOwnProperty.call(stats.compilation.assets, file)) { + expect(stats.compilation.assets[file].source()).toMatchSnapshot(file); + } + } + }); + }); + + it('binds one event handler', () => { + expect(eventBindings.length).toBe(1); + }); + + describe('compilation handler', () => { + beforeEach(() => { + [eventBinding] = eventBindings; + }); + + it('binds to compilation event', () => { + expect(eventBinding.name).toBe('compilation'); + }); + + describe('when called', () => { + let chunkPluginEnvironment; + let compilationEventBindings; + let compilationEventBinding; + let compilation; + let callback; + + beforeEach(() => { + chunkPluginEnvironment = new PluginEnvironment(); + compilation = chunkPluginEnvironment.getEnvironmentStub(); + compilation.assets = { + 'test.js': {}, + 'test1.js': '', + 'test2.js': { + source: () => 'invalid javascript', + }, + 'test3.js': { + source: () => '/** @preserve Foo Bar */ function foo(longVariableName) { longVariableName = 1; }', + }, + }; + compilation.errors = []; + + eventBinding.handler(compilation); + compilationEventBindings = chunkPluginEnvironment.getEventBindings(); + }); + + it('binds one event handler', () => { + expect(compilationEventBindings.length).toBe(1); + }); + + describe('optimize-chunk-assets handler', () => { + beforeEach(() => { + [compilationEventBinding] = compilationEventBindings; + }); + + it('binds to optimize-chunk-assets event', () => { + expect(compilationEventBinding.name).toEqual('optimize-chunk-assets'); + }); + + it('only calls callback once', () => { + callback = jest.fn(); + compilationEventBinding.handler([''], callback); + expect(callback.mock.calls.length).toBe(1); + }); + + it('default only parses filenames ending with .js', () => { + compilationEventBinding.handler([{ + files: ['test', 'test.js'], + }], () => { + expect(Object.keys(compilation.assets).length).toBe(4); + }); + }); + + it('early returns if private property is already set', () => { + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + expect(compilation.assets['test.js']).toEqual({}); + }); + }); + + it('outputs stack trace errors for invalid asset', () => { + compilationEventBinding.handler([{ + files: ['test1.js'], + }], () => { + expect(compilation.errors.length).toBe(1); + expect(compilation.errors[0]).toBeInstanceOf(Error); + expect(compilation.errors[0].message).toEqual(expect.stringContaining('TypeError')); + }); + }); + + it('outputs parsing errors for invalid javascript', () => { + compilationEventBinding.handler([{ + files: ['test2.js'], + }], () => { + expect(compilation.errors.length).toBe(1); + expect(compilation.errors[0]).toBeInstanceOf(Error); + expect(compilation.errors[0].message).toEqual(expect.stringContaining('Unexpected token')); + expect(compilation.errors[0].message).toEqual(expect.stringContaining('[test2.js:1,8]')); + }); + }); + + it('outputs no errors for valid javascript', () => { + compilationEventBinding.handler([{ + files: ['test3.js'], + }], () => { + expect(compilation.errors.length).toBe(0); + }); + }); + + it('outputs RawSource for valid javascript', () => { + compilationEventBinding.handler([{ + files: ['test3.js'], + }], () => { + expect(compilation.assets['test3.js']).toBeInstanceOf(RawSource); + }); + }); + + it('outputs mangled javascript', () => { + compilationEventBinding.handler([{ + files: ['test3.js'], + }], () => { + // eslint-disable-next-line no-underscore-dangle + expect(compilation.assets['test3.js']._value) + .not.toEqual(expect.stringContaining('longVariableName')); + }); + }); + + it('compresses and does not output beautified javascript', () => { + compilationEventBinding.handler([{ + files: ['test3.js'], + }], () => { + // eslint-disable-next-line no-underscore-dangle + expect(compilation.assets['test3.js']._value).not.toEqual(expect.stringContaining('\n')); + }); + }); + + it('preserves comments', () => { + compilationEventBinding.handler([{ + files: ['test3.js'], + }], () => { + // eslint-disable-next-line no-underscore-dangle + expect(compilation.assets['test3.js']._value).toEqual(expect.stringContaining('/**')); + }); + }); + }); + }); + }); +}); diff --git a/__tests__/extract-comments-options.test.js b/__tests__/extract-comments-options.test.js new file mode 100644 index 00000000..3ea84b27 --- /dev/null +++ b/__tests__/extract-comments-options.test.js @@ -0,0 +1,139 @@ +import UglifyJsPlugin from '../src/index'; +import { PluginEnvironment } from './helpers'; + +describe('when options.extractComments', () => { + let compilation; + let compilationEventBinding; + + beforeEach(() => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin({ + compress: { + warnings: true, + }, + comments: false, + extractComments: 1, + mangle: { + props: { + builtins: true, + }, + }, + }); + plugin.apply(compilerEnv); + + const [eventBinding] = pluginEnvironment.getEventBindings(); + const chunkPluginEnvironment = new PluginEnvironment(); + + compilation = chunkPluginEnvironment.getEnvironmentStub(); + compilation.assets = { + 'test.js': { + source: () => 'var foo = 1;', + }, + 'test1.js': { + source: () => 'function foo(x) { if (x) { return bar(); not_called1(); } }', + map: () => { + return { + version: 3, + sources: ['test1.js'], + names: ['foo', 'x', 'bar', 'not_called1'], + mappings: 'AAAA,QAASA,KAAIC,GACT,GAAIA,EAAG,CACH,MAAOC,MACPC', + }; + }, + }, + }; + compilation.warnings = []; + compilation.errors = []; + + eventBinding.handler(compilation); + [compilationEventBinding] = chunkPluginEnvironment.getEventBindings(); + }); + + it('normalizes extractConmments', () => { + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + expect(compilation.errors.length).toBe(0); + }); + }); + + it('outputs warnings for unreachable code', () => { + compilationEventBinding.handler([{ + files: ['test.js', 'test1.js'], + }], () => { + expect(compilation.warnings.length).toBe(1); + expect(compilation.warnings[0]).toBeInstanceOf(Error); + expect(compilation.warnings[0].message).toEqual(expect.stringContaining('Dropping unreachable code')); + }); + }); + + describe('normalizes when options.extractComments is regex', () => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin({ + comments: false, + extractComments: /foo/, + }); + plugin.apply(compilerEnv); + const [eventBinding] = pluginEnvironment.getEventBindings(); + const chunkPluginEnvironment = new PluginEnvironment(); + const compilation2 = chunkPluginEnvironment.getEnvironmentStub(); + compilation2.assets = { + 'test.js': { + source: () => 'var foo = 1;', + }, + }; + compilation2.errors = []; + + eventBinding.handler(compilation2); + [compilationEventBinding] = chunkPluginEnvironment.getEventBindings(); + + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + expect(compilation2.errors.length).toBe(0); + }); + }); + + describe('converts boolean options.extractComments.condition to function', () => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin({ + comments: false, + extractComments: { + condition: true, + filename(file) { + return file.replace(/(\.\w+)$/, '.license$1'); + }, + banner(licenseFile) { + return `License information can be found in ${licenseFile}`; + }, + }, + }); + plugin.apply(compilerEnv); + const [eventBinding] = pluginEnvironment.getEventBindings(); + const chunkPluginEnvironment = new PluginEnvironment(); + const compilation2 = chunkPluginEnvironment.getEnvironmentStub(); + compilation2.assets = { + 'test.js': { + source: () => 'var foo = 1;', + }, + }; + compilation2.errors = []; + + eventBinding.handler(compilation2); + [compilationEventBinding] = chunkPluginEnvironment.getEventBindings(); + + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + expect(compilation2.errors.length).toBe(0); + }); + }); +}); diff --git a/__tests__/extract-option-set-to-a-single-file.test.js b/__tests__/extract-option-set-to-a-single-file.test.js new file mode 100644 index 00000000..ad7ee987 --- /dev/null +++ b/__tests__/extract-option-set-to-a-single-file.test.js @@ -0,0 +1,99 @@ +import UglifyJsPlugin from '../src/index'; +import { PluginEnvironment } from './helpers'; + +describe('when applied with extract option set to a single file', () => { + let eventBindings; + let eventBinding; + + beforeEach(() => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin({ + comments: 'all', + extractComments: { + condition: /.*/, + filename: 'extracted-comments.js', + }, + }); + plugin.apply(compilerEnv); + eventBindings = pluginEnvironment.getEventBindings(); + }); + + it('binds one event handler', () => { + expect(eventBindings.length).toBe(1); + }); + + describe('compilation handler', () => { + beforeEach(() => { + [eventBinding] = eventBindings; + }); + + it('binds to compilation event', () => { + expect(eventBinding.name).toBe('compilation'); + }); + + describe('when called', () => { + let chunkPluginEnvironment; + let compilationEventBindings; + let compilationEventBinding; + let compilation; + + beforeEach(() => { + chunkPluginEnvironment = new PluginEnvironment(); + compilation = chunkPluginEnvironment.getEnvironmentStub(); + compilation.assets = { + 'test.js': { + source: () => '/* This is a comment from test.js */ function foo(bar) { return bar; }', + }, + 'test2.js': { + source: () => '// This is a comment from test2.js\nfunction foo2(bar) { return bar; }', + }, + 'test3.js': { + source: () => '/* This is a comment from test3.js */ function foo3(bar) { return bar; }\n// This is another comment from test3.js\nfunction foobar3(baz) { return baz; }', + }, + }; + compilation.errors = []; + compilation.warnings = []; + + eventBinding.handler(compilation); + compilationEventBindings = chunkPluginEnvironment.getEventBindings(); + }); + + it('binds one event handler', () => { + expect(compilationEventBindings.length).toBe(1); + }); + + describe('optimize-chunk-assets handler', () => { + beforeEach(() => { + [compilationEventBinding] = compilationEventBindings; + }); + + it('preserves comments', () => { + compilationEventBinding.handler([{ + files: ['test.js', 'test2.js', 'test3.js'], + }], () => { + expect(compilation.assets['test.js'].source()).toEqual(expect.stringContaining('/*')); + expect(compilation.assets['test2.js'].source()).toEqual(expect.stringContaining('//')); + expect(compilation.assets['test3.js'].source()).toEqual(expect.stringContaining('/*')); + expect(compilation.assets['test3.js'].source()).toEqual(expect.stringContaining('//')); + }); + }); + + it('extracts comments to specified file', () => { + compilationEventBinding.handler([{ + files: ['test.js', 'test2.js', 'test3.js'], + }], () => { + expect(compilation.errors.length).toBe(0); + expect(compilation.assets['extracted-comments.js'].source()).toEqual(expect.stringContaining('/* This is a comment from test.js */')); + expect(compilation.assets['extracted-comments.js'].source()).toEqual(expect.stringContaining('// This is a comment from test2.js')); + expect(compilation.assets['extracted-comments.js'].source()).toEqual(expect.stringContaining('/* This is a comment from test3.js */')); + expect(compilation.assets['extracted-comments.js'].source()).toEqual(expect.stringContaining('// This is another comment from test3.js')); + expect(compilation.assets['extracted-comments.js'].source()).not.toEqual(expect.stringContaining('function')); + }); + }); + }); + }); + }); +}); diff --git a/__tests__/helpers.js b/__tests__/helpers.js new file mode 100644 index 00000000..d6b89378 --- /dev/null +++ b/__tests__/helpers.js @@ -0,0 +1,63 @@ +import MemoryFileSystem from 'memory-fs'; +import webpack from 'webpack'; + +exports.PluginEnvironment = class PluginEnvironment { + constructor() { + this.events = []; + } + + getEnvironmentStub() { + return { + plugin: (name, handler) => { + this.events.push({ + name, + handler, + }); + }, + }; + } + + getEventBindings() { + return this.events; + } +}; + +exports.compile = function compile(compiler) { + return new Promise((resolve, reject) => { + compiler.run((err, stats) => { // eslint-disable-line consistent-return + if (err) return reject(err); + resolve(stats); + }); + }); +}; + +exports.createCompiler = function createCompiler(options) { + const compiler = webpack(options || { + bail: true, + cache: false, + entry: `${__dirname}/stubs/entry.js`, + output: { + path: `${__dirname}/dist`, + filename: '[name].js', + }, + plugins: [ + new webpack.optimize.CommonsChunkPlugin({ + name: 'manifest', + }), + ], + }); + compiler.outputFileSystem = new MemoryFileSystem(); + return compiler; +}; + +exports.removeCWD = function removeCWD(str) { + return str.split(`${process.cwd()}/`).join(''); +}; + +exports.cleanErrorStack = function cleanErrorStack(error) { + return exports.removeCWD(error.toString()) + .replace(/\n(\s+)(.*)\((.*)\)/g, '\n$1$3') + .replace(/\(|\)/g, '') + .replace(/at /g, ''); +}; + diff --git a/__tests__/invalid-options.test.js b/__tests__/invalid-options.test.js new file mode 100644 index 00000000..ed2ccb10 --- /dev/null +++ b/__tests__/invalid-options.test.js @@ -0,0 +1,66 @@ +import UglifyJsPlugin from '../src/index'; +import { + PluginEnvironment, + cleanErrorStack, + createCompiler, + compile, +} from './helpers'; + +describe('when applied with invalid options', () => { + it('matches snapshot', () => { + const compiler = createCompiler(); + new UglifyJsPlugin({ + output: { + 'invalid-option': true, + }, + }).apply(compiler); + + return compile(compiler).then((stats) => { + const errors = stats.compilation.errors.map(cleanErrorStack); + const warnings = stats.compilation.warnings.map(cleanErrorStack); + + expect(errors).toMatchSnapshot('errors'); + expect(warnings).toMatchSnapshot('warnings'); + + for (const file in stats.compilation.assets) { + if (Object.prototype.hasOwnProperty.call(stats.compilation.assets, file)) { + expect(stats.compilation.assets[file].source()).toMatchSnapshot(file); + } + } + }); + }); + + it('outputs uglify errors', () => { + const pluginEnvironment = new PluginEnvironment(); + const compilerEnv = pluginEnvironment.getEnvironmentStub(); + compilerEnv.context = ''; + + const plugin = new UglifyJsPlugin({ + output: { + 'invalid-option': true, + }, + }); + plugin.apply(compilerEnv); + const [eventBinding] = pluginEnvironment.getEventBindings(); + + const chunkPluginEnvironment = new PluginEnvironment(); + const compilation = chunkPluginEnvironment.getEnvironmentStub(); + compilation.assets = { + 'test.js': { + source: () => 'var foo = 1;', + }, + }; + compilation.errors = []; + + eventBinding.handler(compilation); + const [compilationEventBinding] = chunkPluginEnvironment.getEventBindings(); + + compilationEventBinding.handler([{ + files: ['test.js'], + }], () => { + expect(compilation.errors.length).toBe(1); + expect(compilation.errors[0]).toBeInstanceOf(Error); + expect(compilation.errors[0].message).toEqual(expect.stringContaining('from UglifyJs')); + }); + }); +}); diff --git a/__tests__/stubs/entry.js b/__tests__/stubs/entry.js new file mode 100644 index 00000000..a2699b26 --- /dev/null +++ b/__tests__/stubs/entry.js @@ -0,0 +1,9 @@ +// foo +/*@preserve*/ +// bar +var a = 2 + 2; + +module.exports = function Foo() { + var b = 2 + 2; + console.log(b + 1 + 2); +}; diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..b8fd7023 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,17 @@ +codecov: + branch: master +coverage: + precision: 2 + round: down + range: "70...100" + status: + project: + default: + target: auto + patch: + default: + target: auto + changes: + default: + branches: null +comment: off diff --git a/package-lock.json b/package-lock.json index d13797be..ab89a075 100644 --- a/package-lock.json +++ b/package-lock.json @@ -87,9 +87,9 @@ "dev": true }, "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz", + "integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=", "dev": true }, "ansi-regex": { @@ -104,12 +104,6 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "ansicolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz", - "integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=", - "dev": true - }, "anymatch": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", @@ -182,6 +176,12 @@ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", "dev": true }, + "array.prototype.find": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", + "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", + "dev": true + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -345,9 +345,9 @@ "dev": true }, "babel-jest": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-18.0.0.tgz", - "integrity": "sha1-F+u6jLMoXJBthZ6HB+Tnl5X7ZeM=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz", + "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=", "dev": true }, "babel-messages": { @@ -363,15 +363,15 @@ "dev": true }, "babel-plugin-istanbul": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-3.1.2.tgz", - "integrity": "sha1-EdWr3hhCXsJLXWSMfgtdJc01SiI=", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.4.tgz", + "integrity": "sha1-GN3oS/POMp/d8/QQP66SFFbY5Yc=", "dev": true }, "babel-plugin-jest-hoist": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-18.0.0.tgz", - "integrity": "sha1-QVDnDsq1YObnNErchJSYBy004So=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-20.0.3.tgz", + "integrity": "sha1-r+3IU70/jcNUjqZx++adA8wsF2c=", "dev": true }, "babel-plugin-syntax-async-functions": { @@ -573,9 +573,9 @@ "dev": true }, "babel-preset-jest": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-18.0.0.tgz", - "integrity": "sha1-hPr4yj7GWrp9Xj9Zu67ZNaskBJ4=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-20.0.3.tgz", + "integrity": "sha1-y6yq3stdaJyh4d4TYOv8ZoYsF4o=", "dev": true }, "babel-register": { @@ -746,9 +746,9 @@ "dev": true }, "bser": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", - "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", "dev": true }, "buffer": { @@ -850,12 +850,6 @@ "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", "dev": true }, - "cardinal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz", - "integrity": "sha1-UOIcGwqjdyn5N33vGWtanOyTLuk=", - "dev": true - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -904,9 +898,9 @@ "dev": true }, "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", "dev": true }, "cli-spinners": { @@ -915,12 +909,6 @@ "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=", "dev": true }, - "cli-table": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", - "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", - "dev": true - }, "cli-truncate": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", @@ -941,12 +929,6 @@ } } }, - "cli-usage": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/cli-usage/-/cli-usage-0.1.4.tgz", - "integrity": "sha1-fAHg3HBsI0s5yTODjI4gshdXduI=", - "dev": true - }, "cli-width": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", @@ -970,10 +952,16 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "color-convert": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", + "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", + "dev": true + }, + "color-name": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.2.tgz", + "integrity": "sha1-XIq3K2S9IhXWF66VWeuxSEdc+Y0=", "dev": true }, "combined-stream": { @@ -1256,6 +1244,12 @@ "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", "dev": true }, + "damerau-levenshtein": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", + "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", + "dev": true + }, "dargs": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", @@ -1323,6 +1317,12 @@ "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true + }, "del": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", @@ -1446,6 +1446,18 @@ "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true }, + "es-abstract": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.7.0.tgz", + "integrity": "sha1-363ndOAb/Nl/lhgCmMRJyGI/uUw=", + "dev": true + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true + }, "es5-ext": { "version": "0.10.23", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.23.tgz", @@ -1522,24 +1534,10 @@ "dev": true }, "eslint": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", - "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", - "dev": true, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "user-home": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", - "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", - "dev": true - } - } + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.1.1.tgz", + "integrity": "sha1-+svfz+Pg+s06i4DcmMTmwTrlgt8=", + "dev": true }, "eslint-config-webpack": { "version": "1.2.5", @@ -1571,12 +1569,6 @@ "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true - }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -1609,6 +1601,44 @@ } } }, + "eslint-plugin-jest": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-20.0.3.tgz", + "integrity": "sha1-7BXrpqwKtEpn6/bgJnLKnX58uik=", + "dev": true + }, + "eslint-plugin-jsx-a11y": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-3.0.2.tgz", + "integrity": "sha1-nw6ryv3j0qJgDZamatuQ0JnoQf4=", + "dev": true + }, + "eslint-plugin-node": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.2.tgz", + "integrity": "sha1-gpWcqa7Xn8vSi7GxiNBcrAT7M2M=", + "dev": true + }, + "eslint-plugin-react": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", + "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", + "dev": true, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true + } + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true + }, "espree": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", @@ -1699,6 +1729,12 @@ "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "dev": true }, + "external-editor": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz", + "integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=", + "dev": true + }, "extglob": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", @@ -1711,6 +1747,12 @@ "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", "dev": true }, + "fast-deep-equal": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-0.1.0.tgz", + "integrity": "sha1-XG9FmaumszPuM0Li7ZeGcvEAH40=", + "dev": true + }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", @@ -1718,15 +1760,15 @@ "dev": true }, "fb-watchman": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", - "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", "dev": true }, "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true }, "file-entry-cache": { @@ -1754,9 +1796,9 @@ "dev": true }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true }, "flat-cache": { @@ -1791,6 +1833,12 @@ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2534,6 +2582,12 @@ } } }, + "git-prepush-hook": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/git-prepush-hook/-/git-prepush-hook-1.0.2.tgz", + "integrity": "sha1-rgxKz69t/PBY5Ogv4TqgnwzlCT0=", + "dev": true + }, "git-raw-commits": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-1.2.0.tgz", @@ -2552,6 +2606,12 @@ "integrity": "sha1-sx/QLIq1eL1sm1ysyl4cZMEXesE=", "dev": true }, + "git-validate": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/git-validate/-/git-validate-2.2.2.tgz", + "integrity": "sha1-nMj/ABF3lXoRcmq1CNQVu4Cxi88=", + "dev": true + }, "gitconfiglocal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", @@ -2729,9 +2789,9 @@ "dev": true }, "iconv-lite": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", - "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", "dev": true }, "ieee754": { @@ -2789,24 +2849,10 @@ "dev": true }, "inquirer": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", - "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true - } - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.1.1.tgz", + "integrity": "sha512-H50sHQwgvvaTBd3HpKMVtL/u6LoHDvYym51gd7bGQe/+9HkCE+J0/3N5FJLfd6O6oz44hHewC2Pc2LodzWVafQ==", + "dev": true }, "interpret": { "version": "1.0.3", @@ -2849,12 +2895,24 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, "is-ci": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz", "integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=", "dev": true }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", @@ -2969,6 +3027,12 @@ "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", "dev": true }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true + }, "is-resolvable": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", @@ -2993,6 +3057,12 @@ "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", "dev": true }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, "is-text-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", @@ -3092,11 +3162,17 @@ "dev": true }, "jest": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-18.1.0.tgz", - "integrity": "sha1-vOvx4gPe5cKtIJHIBTAKND2ebH0=", + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest/-/jest-20.0.4.tgz", + "integrity": "sha1-PdJgwpidba1nix6cxNkZRPbWAqw=", "dev": true, "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, "callsites": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", @@ -3122,9 +3198,9 @@ "dev": true }, "jest-cli": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-18.1.0.tgz", - "integrity": "sha1-Xq027K1CCBfCybqiqnV09jJXs9Y=", + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-20.0.4.tgz", + "integrity": "sha1-5TKxnYiuW8bEF+iwWTpv6VSx3JM=", "dev": true }, "string-width": { @@ -3134,95 +3210,107 @@ "dev": true }, "yargs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", - "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", "dev": true } } }, "jest-changed-files": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-17.0.2.tgz", - "integrity": "sha1-9WV3WHNplvWQpRuH5ck2nZBLp7c=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-20.0.3.tgz", + "integrity": "sha1-k5TVzGXEOEBhSb7xv01Sto4D4/g=", "dev": true }, "jest-config": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-18.1.0.tgz", - "integrity": "sha1-YRF0Cm1Iqrhv9anmqwuYvZk7b/Q=", + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-20.0.4.tgz", + "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=", "dev": true }, "jest-diff": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-18.1.0.tgz", - "integrity": "sha1-T/eedN2YjBORlbNl3GXYf2BvSAM=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz", + "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=", "dev": true }, - "jest-environment-jsdom": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-18.1.0.tgz", - "integrity": "sha1-GLQvDE6iuunzbKs2ObHo+MOE4k4=", + "jest-docblock": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-20.0.3.tgz", + "integrity": "sha1-F76phDQswz2DxQ++FUXqDvqkRxI=", "dev": true }, - "jest-environment-node": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-18.1.0.tgz", - "integrity": "sha1-TWeXVyyN2pms9frmlutilFVHx3k=", + "jest-environment-jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz", + "integrity": "sha1-BIqKwS7iJfcZBBdxODS7mZeH3pk=", "dev": true }, - "jest-file-exists": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/jest-file-exists/-/jest-file-exists-17.0.0.tgz", - "integrity": "sha1-f2Prc6HEOhP0Yb4mF2i0WvLN0Wk=", + "jest-environment-node": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-20.0.3.tgz", + "integrity": "sha1-1Ii8RhKvLCRumG6K52caCZFj1AM=", "dev": true }, "jest-haste-map": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-18.1.0.tgz", - "integrity": "sha1-BoOcdLdwpAwaEGlohR340oHAg3U=", + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.0.4.tgz", + "integrity": "sha1-ZT61XIic48Ah97lGk/IKQVm63wM=", "dev": true }, "jest-jasmine2": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-18.1.0.tgz", - "integrity": "sha1-CU4QTCwYlwh2bHcmO7Kuy1hgqAs=", + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-20.0.4.tgz", + "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=", "dev": true }, "jest-matcher-utils": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-18.1.0.tgz", - "integrity": "sha1-GsRlGVXuKmDO8ef8yYzf13PA+TI=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz", + "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=", "dev": true }, "jest-matchers": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-18.1.0.tgz", - "integrity": "sha1-A0FIS/h6H9C6wKTSyJnit3o/Hq0=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz", + "integrity": "sha1-ymnbHDLbWm9wf6XgQBq7VXAN/WA=", + "dev": true + }, + "jest-message-util": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz", + "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=", "dev": true }, "jest-mock": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-18.0.0.tgz", - "integrity": "sha1-XCSIRuoz+lWLUm9TEqtKZ2XkibM=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-20.0.3.tgz", + "integrity": "sha1-i8Bw6QQUqhVcEajWTIaaDVxx2lk=", + "dev": true + }, + "jest-regex-util": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-20.0.3.tgz", + "integrity": "sha1-hburXRM+RGJbGfr4xqpRItCF12I=", "dev": true }, "jest-resolve": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-18.1.0.tgz", - "integrity": "sha1-aACsy1NmWMkGzV4p3kErGrmsJJs=", + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-20.0.4.tgz", + "integrity": "sha1-lEiz6La6/BVHlETGSZBFt//ll6U=", "dev": true }, "jest-resolve-dependencies": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-18.1.0.tgz", - "integrity": "sha1-gTT7XK9Zye2EL+AVKrAcUnEfG7s=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-20.0.3.tgz", + "integrity": "sha1-bhSntxevDyyzZnxUneQK8Bexcjo=", "dev": true }, "jest-runtime": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-18.1.0.tgz", - "integrity": "sha1-Or/WhxdbIfw7haK4BkOZ6ZeFmSI=", + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-20.0.4.tgz", + "integrity": "sha1-osgCIZxCA/dU3xQE5JAYYWnRJNg=", "dev": true, "dependencies": { "camelcase": { @@ -3249,30 +3337,42 @@ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "yargs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", - "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", "dev": true } } }, "jest-snapshot": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-18.1.0.tgz", - "integrity": "sha1-VbltLuY5ybznb4fyo/1Atxx6WRY=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-20.0.3.tgz", + "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=", "dev": true }, "jest-util": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-18.1.0.tgz", - "integrity": "sha1-OpnDIRSrF/hL4JQ4JScAbm1L/Go=", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-20.0.3.tgz", + "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=", + "dev": true + }, + "jest-validate": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-20.0.3.tgz", + "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=", "dev": true }, "js-tokens": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz", - "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", "dev": true }, "js-yaml": { @@ -3288,6 +3388,12 @@ "dev": true, "optional": true }, + "jschardet": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.4.2.tgz", + "integrity": "sha1-KqEH8UKvQSHRRWWdRPUIMJYeaZo=", + "dev": true + }, "jsdom": { "version": "9.12.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", @@ -3320,6 +3426,12 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, "json-stable-stringify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", @@ -3376,6 +3488,12 @@ } } }, + "jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", + "dev": true + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -3398,6 +3516,12 @@ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -3405,9 +3529,9 @@ "dev": true }, "lint-staged": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-3.6.1.tgz", - "integrity": "sha1-JEI8i3vZnZbhWs0ayMs5KnjlhYI=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-4.0.0.tgz", + "integrity": "sha1-wVZp9ZhhSm5oCQMD4XWnmdSODYU=", "dev": true, "dependencies": { "execa": { @@ -3434,7 +3558,15 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/listr/-/listr-0.12.0.tgz", "integrity": "sha1-a84sD1YD+klYDqF81qAMwOX6RRo=", - "dev": true + "dev": true, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true + } + } }, "listr-silent-renderer": { "version": "1.1.1", @@ -3448,6 +3580,12 @@ "integrity": "sha1-yoDhd5tOcCZoB+ju0a1qvjmFUPk=", "dev": true, "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true + }, "indent-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.1.0.tgz", @@ -3460,7 +3598,33 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.0.tgz", "integrity": "sha1-RNwBuww0oDxXIVTU0Izemx3FYg8=", - "dev": true + "dev": true, + "dependencies": { + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true + } + } }, "load-json-file": { "version": "1.1.0", @@ -3475,24 +3639,16 @@ "dev": true }, "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", "dev": true }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } + "dev": true }, "lodash": { "version": "4.17.4", @@ -3500,102 +3656,24 @@ "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", "dev": true }, - "lodash._arraycopy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", - "integrity": "sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=", - "dev": true - }, - "lodash._arrayeach": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", - "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=", - "dev": true - }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", - "dev": true - }, - "lodash._baseclone": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", - "integrity": "sha1-MDUZv2OT/n5C802LYw73eU41Qrc=", - "dev": true - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basefor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", - "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=", - "dev": true - }, - "lodash._bindcallback": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", - "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "dev": true - }, "lodash.chunk": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", "integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=", "dev": true }, - "lodash.clonedeep": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", - "integrity": "sha1-oKHkDYKl6on/WxR7hETtY9koJ9s=", - "dev": true - }, "lodash.cond": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", "dev": true }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true - }, "lodash.template": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", @@ -3618,7 +3696,33 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", - "dev": true + "dev": true, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true + } + } }, "longest": { "version": "1.0.1", @@ -3667,18 +3771,6 @@ "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", "dev": true }, - "marked": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", - "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=", - "dev": true - }, - "marked-terminal": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-1.7.0.tgz", - "integrity": "sha1-yMRgiBx3LHYEtkNnAH7l938SWQQ=", - "dev": true - }, "mem": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", @@ -3798,9 +3890,9 @@ "dev": true }, "mute-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", - "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, "nan": { @@ -3822,12 +3914,6 @@ "integrity": "sha1-mLL/rvtGEPo5NvHnFDXTBwDeKEA=", "dev": true }, - "node-emoji": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.5.1.tgz", - "integrity": "sha1-/ZGOQSdpv4xEgFEjgjOECyr/FqE=", - "dev": true - }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -3849,18 +3935,10 @@ } }, "node-notifier": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-4.6.1.tgz", - "integrity": "sha1-BW0UJE89zBzq3+aK+c/wxUc6M/M=", - "dev": true, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.1.2.tgz", + "integrity": "sha1-L6nhJgX6EACdRFSdb82KY93g5P8=", + "dev": true }, "normalize-package-data": { "version": "2.4.0", @@ -4188,6 +4266,18 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object.assign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "dev": true + }, "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", @@ -4201,9 +4291,9 @@ "dev": true }, "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", "dev": true }, "optimist": { @@ -4230,7 +4320,27 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", - "dev": true + "dev": true, + "dependencies": { + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true + } + } }, "os-browserify": { "version": "0.2.1", @@ -4341,9 +4451,9 @@ "dev": true }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-is-absolute": { @@ -4410,12 +4520,26 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true + "dev": true, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true + } + } }, "pluralize": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-4.0.0.tgz", + "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=", "dev": true }, "pre-commit": { @@ -4443,10 +4567,18 @@ "dev": true }, "pretty-format": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-18.1.0.tgz", - "integrity": "sha1-+2Wob3p/kZSWPu6RhlwbzxA54oQ=", - "dev": true + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz", + "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=", + "dev": true, + "dependencies": { + "ansi-styles": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", + "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", + "dev": true + } + } }, "private": { "version": "0.1.7", @@ -4467,9 +4599,9 @@ "dev": true }, "progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", "dev": true }, "prop-ini": { @@ -4584,7 +4716,21 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true + "dev": true, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true + } + } }, "readable-stream": { "version": "2.3.2", @@ -4598,52 +4744,18 @@ "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", "dev": true }, - "readline2": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", - "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true - } - } - }, "readme-badger": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/readme-badger/-/readme-badger-0.1.2.tgz", "integrity": "sha1-gbE435cjxzPfaifHvZyuvTg+CKU=", "dev": true }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true - }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true }, - "redeyed": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz", - "integrity": "sha1-6WwZO0DAgWsArshCaY5hGF5VSYo=", - "dev": true, - "dependencies": { - "esprima": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz", - "integrity": "sha1-U88kes2ncxPlUcOqLnM0LT+099k=", - "dev": true - } - } - }, "regenerate": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz", @@ -4772,9 +4884,9 @@ "dev": true }, "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true }, "right-align": { @@ -4795,15 +4907,21 @@ "dev": true }, "run-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", - "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", "dev": true }, "rx-lite": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", - "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", "dev": true }, "rxjs": { @@ -4819,11 +4937,23 @@ "dev": true }, "sane": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sane/-/sane-1.4.1.tgz", - "integrity": "sha1-iPdj10BA9fDCVrYWPbOZvxEKxxU=", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz", + "integrity": "sha1-lhDEUjB6E10pwf3+JUcDQYDEZ3U=", "dev": true, "dependencies": { + "bser": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", + "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", + "dev": true + }, + "fb-watchman": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", + "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", + "dev": true + }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", @@ -4886,12 +5016,6 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, - "shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "dev": true - }, "shellwords": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz", @@ -5050,10 +5174,10 @@ "integrity": "sha1-3j+4XLjW6RyFvLzrFkWBeFy1ezY=", "dev": true }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "dev": true }, "get-stream": { @@ -5160,6 +5284,12 @@ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", "dev": true }, + "string-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", + "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=", + "dev": true + }, "string-width": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", @@ -5180,12 +5310,6 @@ } } }, - "string.prototype.codepointat": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz", - "integrity": "sha1-aybpvTr8qnvjtCabUm3huCAArHg=", - "dev": true - }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -5246,10 +5370,16 @@ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", "dev": true }, + "sync-exec": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz", + "integrity": "sha1-cX0izFPwzh3vVZQ2LzqJouu5EQU=", + "dev": true + }, "table": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", - "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", + "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", "dev": true }, "tapable": { @@ -5265,9 +5395,9 @@ "dev": true }, "test-exclude": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-3.3.0.tgz", - "integrity": "sha1-ehfKEjmYjJg2ewYhRW27fUvDiXc=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", + "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", "dev": true }, "text-extensions": { @@ -5312,6 +5442,12 @@ "integrity": "sha1-q0iDz1l9zVCvIRNJoA+8pWrIa4Y=", "dev": true }, + "tmp": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "dev": true + }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", @@ -5408,6 +5544,12 @@ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "optional": true }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true + }, "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", @@ -5527,11 +5669,23 @@ "dev": true }, "webpack": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-2.6.1.tgz", - "integrity": "sha1-LgRX8KuxrF3zqxBsacZy8jZ4Xwc=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.0.0.tgz", + "integrity": "sha1-7pvOvyEkf3FTy0EBaMq0XjpZ1Nc=", "dev": true, "dependencies": { + "ajv": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.0.tgz", + "integrity": "sha1-wXNQJMXaLvdcwZBxMHPUTwmL9IY=", + "dev": true + }, + "ajv-keywords": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.0.tgz", + "integrity": "sha1-opbhf3v658HOT34N5T0pyzIWLfA=", + "dev": true + }, "camelcase": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", @@ -5550,12 +5704,6 @@ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true }, - "source-list-map": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-1.1.2.tgz", - "integrity": "sha1-mIkBnRAkzOVc3AaUmDN+9hhqEaE=", - "dev": true - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -5568,17 +5716,17 @@ "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true }, - "webpack-sources": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.2.3.tgz", - "integrity": "sha1-F8Yr+vE8cH+dAsR54Nzd6DgGl/s=", - "dev": true - }, "yargs": { "version": "6.6.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", "dev": true + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true } } }, @@ -5603,7 +5751,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", - "dev": true + "dev": true, + "dependencies": { + "iconv-lite": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", + "dev": true + } + } }, "whatwg-url": { "version": "4.8.0", @@ -5741,9 +5897,9 @@ "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=" }, "yargs-parser": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", - "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", "dev": true, "dependencies": { "camelcase": { diff --git a/package.json b/package.json index 29b75deb..7b5004bf 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "start": "npm run build -- -w", "build": "cross-env NODE_ENV=production babel src -d dist --ignore 'src/**/*.test.js'", + "test:all": "npm run test:coverage && npm run test:lint", "test": "jest", "test:coverage": "jest --collectCoverageFrom='src/**/*.js' --coverage", "test:watch": "jest --watch", @@ -23,6 +24,10 @@ "appveyor:test": "npm run test", "webpack-defaults": "webpack-defaults" }, + "repository": { + "type": "git", + "url": "https://github.com/webpack-contrib/uglifyjs-webpack-plugin.git" + }, "keywords": [ "webpack", "uglifyjs", @@ -31,6 +36,22 @@ "files": [ "dist" ], + "jest": { + "testEnvironment": "node", + "transform": { + "^.+\\.js$": "/node_modules/babel-jest" + }, + "testRegex": "(/__tests__/.*\\.(test))\\.js$", + "transformIgnorePatterns": [ + "[/\\\\]node_modules[/\\\\].+\\.js$" + ] + }, + "author": "webpack Contrib Team", + "license": "MIT", + "bugs": { + "url": "https://github.com/webpack-contrib/uglifyjs-webpack-plugin/issues" + }, + "homepage": "https://github.com/webpack-contrib/uglifyjs-webpack-plugin", "peerDependencies": { "webpack": "^2.0.0 || ^3.0.0" }, @@ -53,11 +74,18 @@ "eslint": "^4.1.1", "eslint-config-webpack": "^1.2.3", "eslint-plugin-import": "^2.2.0", + "eslint-plugin-jest": "^20.0.3", + "eslint-plugin-jsx-a11y": "^3.0.2", + "eslint-plugin-node": "^4.0.1", + "eslint-plugin-react": "^6.9.0", + "git-prepush-hook": "^1.0.1", "jest": "^20.0.4", "lint-staged": "^4.0.0", + "memory-fs": "^0.4.1", "nsp": "^2.6.3", "pre-commit": "^1.2.2", "standard-version": "^4.1.0", + "sync-exec": "^0.6.2", "uglify-js": "^2.8.18", "webpack": "^3.0.0", "webpack-defaults": "^1.4.0" @@ -72,14 +100,5 @@ "git add" ] }, - "author": "webpack Contrib Team", - "repository": { - "type": "git", - "url": "https://github.com/webpack-contrib/uglifyjs-webpack-plugin.git" - }, - "bugs": { - "url": "https://github.com/webpack-contrib/uglifyjs-webpack-plugin/issues" - }, - "homepage": "https://github.com/webpack-contrib/uglifyjs-webpack-plugin", - "license": "MIT" + "pre-push": [] } diff --git a/src/index.js b/src/index.js index daa91bb9..217767ea 100644 --- a/src/index.js +++ b/src/index.js @@ -45,8 +45,10 @@ class UglifyJsPlugin { } compilation.plugin('optimize-chunk-assets', (chunks, callback) => { const files = []; - chunks.forEach(chunk => files.push(...chunk.files)); - files.push(...compilation.additionalChunkAssets); + // eslint-disable-next-line prefer-spread + chunks.forEach(chunk => files.push.apply(files, chunk.files)); + // eslint-disable-next-line prefer-spread + files.push.apply(files, compilation.additionalChunkAssets); const filteredFiles = files.filter(ModuleFilenameHelpers.matchObject.bind(undefined, options)); filteredFiles.forEach((file) => { const oldWarnFunction = uglify.AST_Node.warn_function;