diff --git a/.eslintrc b/.eslintrc index ec0923b61..2a8871517 100644 --- a/.eslintrc +++ b/.eslintrc @@ -10,7 +10,6 @@ extends: - plugin:promise/recommended - plugin:import/errors - plugin:import/warnings - - prettier parser: babel-eslint parserOptions: sourceType: module diff --git a/.huskyrc b/.huskyrc index 4d077c829..020941183 100644 --- a/.huskyrc +++ b/.huskyrc @@ -1,5 +1,5 @@ { "hooks": { - "pre-commit": "lint-staged" + "pre-commit": "lint-staged && npm test" } } diff --git a/.lintstagedrc.yml b/.lintstagedrc.yml index b43fedd03..c42ba70ed 100644 --- a/.lintstagedrc.yml +++ b/.lintstagedrc.yml @@ -1,6 +1,5 @@ linters: "*.js": - - "eslint --fix" # Run TSLint - - "prettier --write" # Run Prettier - - "npm test" # Run tests + - "prettier-eslint --write" # Run Prettier + - "eslint" # Run TSLint - "git add" diff --git a/index.js b/index.js index 3032c8cd8..6841c68dc 100644 --- a/index.js +++ b/index.js @@ -17,7 +17,6 @@ const packageModules = require('./lib/packageModules'); const lib = require('./lib'); class ServerlessWebpack { - static get lib() { return lib; } @@ -28,10 +27,10 @@ class ServerlessWebpack { if ( (_.has(this.serverless, 'service.custom.webpack') && - _.isString(this.serverless.service.custom.webpack) && - _.endsWith(this.serverless.service.custom.webpack, '.ts')) || + _.isString(this.serverless.service.custom.webpack) && + _.endsWith(this.serverless.service.custom.webpack, '.ts')) || (_.has(this.serverless, 'service.custom.webpack.webpackConfig') && - _.endsWith(this.serverless.service.custom.webpack.webpackConfig, '.ts')) + _.endsWith(this.serverless.service.custom.webpack.webpackConfig, '.ts')) ) { require('ts-node/register'); } @@ -54,139 +53,131 @@ class ServerlessWebpack { this.commands = { webpack: { usage: 'Bundle with Webpack', - lifecycleEvents: [ - 'webpack' - ], + lifecycleEvents: ['webpack'], options: { out: { usage: 'Path to output directory', - shortcut: 'o', - }, + shortcut: 'o' + } }, commands: { validate: { type: 'entrypoint', - lifecycleEvents: [ - 'validate', - ], + lifecycleEvents: ['validate'] }, compile: { type: 'entrypoint', - lifecycleEvents: [ - 'compile', - ], + lifecycleEvents: ['compile'], commands: { watch: { type: 'entrypoint', - lifecycleEvents: [ - 'compile' - ] + lifecycleEvents: ['compile'] } } }, package: { type: 'entrypoint', - lifecycleEvents: [ - 'packExternalModules', - 'packageModules' - ], - }, - }, - }, + lifecycleEvents: [ 'packExternalModules', 'packageModules' ] + } + } + } }; this.hooks = { - 'before:package:createDeploymentArtifacts': () => BbPromise.bind(this) - .then(() => this.serverless.pluginManager.spawn('webpack:validate')) - .then(() => this.serverless.pluginManager.spawn('webpack:compile')) - .then(() => this.serverless.pluginManager.spawn('webpack:package')), - - 'after:package:createDeploymentArtifacts': () => BbPromise.bind(this) - .then(this.cleanup), - - 'before:deploy:function:packageFunction': () => BbPromise.bind(this) - .then(() => this.serverless.pluginManager.spawn('webpack:validate')) - .then(() => this.serverless.pluginManager.spawn('webpack:compile')) - .then(() => this.serverless.pluginManager.spawn('webpack:package')), - - 'before:invoke:local:invoke': () => BbPromise.bind(this) - .then(() => { - lib.webpack.isLocal = true; - // --no-build override - if (this.options.build === false) { - this.skipCompile = true; - } + 'before:package:createDeploymentArtifacts': () => + BbPromise.bind(this) + .then(() => this.serverless.pluginManager.spawn('webpack:validate')) + .then(() => this.serverless.pluginManager.spawn('webpack:compile')) + .then(() => this.serverless.pluginManager.spawn('webpack:package')), + + 'after:package:createDeploymentArtifacts': () => BbPromise.bind(this).then(this.cleanup), + + 'before:deploy:function:packageFunction': () => + BbPromise.bind(this) + .then(() => this.serverless.pluginManager.spawn('webpack:validate')) + .then(() => this.serverless.pluginManager.spawn('webpack:compile')) + .then(() => this.serverless.pluginManager.spawn('webpack:package')), + + 'before:invoke:local:invoke': () => + BbPromise.bind(this) + .then(() => { + lib.webpack.isLocal = true; + // --no-build override + if (this.options.build === false) { + this.skipCompile = true; + } - return this.serverless.pluginManager.spawn('webpack:validate'); - }) - .then(() => this.skipCompile ? BbPromise.resolve() : this.serverless.pluginManager.spawn('webpack:compile')) - .then(this.prepareLocalInvoke), + return this.serverless.pluginManager.spawn('webpack:validate'); + }) + .then(() => (this.skipCompile ? BbPromise.resolve() : this.serverless.pluginManager.spawn('webpack:compile'))) + .then(this.prepareLocalInvoke), - 'after:invoke:local:invoke': () => BbPromise.bind(this) - .then(() => { + 'after:invoke:local:invoke': () => + BbPromise.bind(this).then(() => { if (this.options.watch && !this.isWatching) { return this.watch('invoke:local'); } return BbPromise.resolve(); }), - 'before:run:run': () => BbPromise.bind(this) - .then(() => _.set(this.serverless, 'service.package.individually', false)) - .then(() => this.serverless.pluginManager.spawn('webpack:validate')) - .then(() => this.serverless.pluginManager.spawn('webpack:compile')) - .then(this.packExternalModules) - .then(this.prepareRun), + 'before:run:run': () => + BbPromise.bind(this) + .then(() => _.set(this.serverless, 'service.package.individually', false)) + .then(() => this.serverless.pluginManager.spawn('webpack:validate')) + .then(() => this.serverless.pluginManager.spawn('webpack:compile')) + .then(this.packExternalModules) + .then(this.prepareRun), - 'after:run:run': () => BbPromise.bind(this) - .then(() => { + 'after:run:run': () => + BbPromise.bind(this).then(() => { if (this.options.watch && !this.isWatching) { return this.watch(this.watchRun.bind(this)); } return BbPromise.resolve(); }), - 'webpack:webpack': () => BbPromise.bind(this) - .then(() => this.serverless.pluginManager.spawn('webpack:validate')) - .then(() => this.serverless.pluginManager.spawn('webpack:compile')) - .then(() => this.serverless.pluginManager.spawn('webpack:package')), + 'webpack:webpack': () => + BbPromise.bind(this) + .then(() => this.serverless.pluginManager.spawn('webpack:validate')) + .then(() => this.serverless.pluginManager.spawn('webpack:compile')) + .then(() => this.serverless.pluginManager.spawn('webpack:package')), /* * Internal webpack events (can be hooked by plugins) */ - 'webpack:validate:validate': () => BbPromise.bind(this) - .then(this.validate), + 'webpack:validate:validate': () => BbPromise.bind(this).then(this.validate), - 'webpack:compile:compile': () => BbPromise.bind(this) - .then(this.compile), + 'webpack:compile:compile': () => BbPromise.bind(this).then(this.compile), 'webpack:compile:watch:compile': () => BbPromise.resolve(), - 'webpack:package:packExternalModules': () => BbPromise.bind(this) - .then(this.packExternalModules), - - 'webpack:package:packageModules': () => BbPromise.bind(this) - .then(this.packageModules), - - 'before:offline:start': () => BbPromise.bind(this) - .tap(() => { - lib.webpack.isLocal = true; - }) - .then(this.prepareOfflineInvoke) - .then(this.wpwatch), - - 'before:offline:start:init': () => BbPromise.bind(this) - .tap(() => { - lib.webpack.isLocal = true; - }) - .then(this.prepareOfflineInvoke) - .then(this.wpwatch), - - 'before:step-functions-offline:start': () => BbPromise.bind(this) - .tap(() => { - lib.webpack.isLocal = true; - }) - .then(this.prepareStepOfflineInvoke) - .then(() => this.serverless.pluginManager.spawn('webpack:compile')), + 'webpack:package:packExternalModules': () => BbPromise.bind(this).then(this.packExternalModules), + + 'webpack:package:packageModules': () => BbPromise.bind(this).then(this.packageModules), + + 'before:offline:start': () => + BbPromise.bind(this) + .tap(() => { + lib.webpack.isLocal = true; + }) + .then(this.prepareOfflineInvoke) + .then(this.wpwatch), + + 'before:offline:start:init': () => + BbPromise.bind(this) + .tap(() => { + lib.webpack.isLocal = true; + }) + .then(this.prepareOfflineInvoke) + .then(this.wpwatch), + + 'before:step-functions-offline:start': () => + BbPromise.bind(this) + .tap(() => { + lib.webpack.isLocal = true; + }) + .then(this.prepareStepOfflineInvoke) + .then(() => this.serverless.pluginManager.spawn('webpack:compile')) }; } } diff --git a/index.test.js b/index.test.js index 1e9c6ca97..c2448c118 100644 --- a/index.test.js +++ b/index.test.js @@ -58,10 +58,15 @@ describe('ServerlessWebpack', () => { it('should expose a lib object', () => { const lib = ServerlessWebpack.lib; expect(lib).to.be.an('object'); - expect(lib).to.have.a.property('entries').that.is.an('object').that.is.empty; - expect(lib).to.have.a.property('webpack').that.is.an('object').that.deep.equals({ - isLocal: false - }); + expect(lib) + .to.have.a.property('entries') + .that.is.an('object').that.is.empty; + expect(lib) + .to.have.a.property('webpack') + .that.is.an('object') + .that.deep.equals({ + isLocal: false + }); }); describe('with a TS webpack configuration', () => { @@ -88,22 +93,25 @@ describe('ServerlessWebpack', () => { }); }); - _.forEach([ - 'commands.webpack', - 'commands.webpack.commands.validate', - 'commands.webpack.commands.compile', - 'commands.webpack.commands.compile.commands.watch', - 'commands.webpack.commands.package', - ], command => { - it(`should expose command/entrypoint ${_.last(_.split(command, '.'))}`, () => { - const slsw = new ServerlessWebpack(serverless, {}); - expect(slsw).to.have.a.nested.property(command); - }); - }); + _.forEach( + [ + 'commands.webpack', + 'commands.webpack.commands.validate', + 'commands.webpack.commands.compile', + 'commands.webpack.commands.compile.commands.watch', + 'commands.webpack.commands.package' + ], + command => { + it(`should expose command/entrypoint ${_.last(_.split(command, '.'))}`, () => { + const slsw = new ServerlessWebpack(serverless, {}); + expect(slsw).to.have.a.nested.property(command); + }); + } + ); describe('hooks', () => { let slsw; - + before(() => { slsw = new ServerlessWebpack(serverless, {}); sandbox.stub(slsw, 'cleanup').returns(BbPromise.resolve()); @@ -128,261 +136,266 @@ describe('ServerlessWebpack', () => { slsw.cleanup.restore(); }); - _.forEach([ - { - name: 'before:package:createDeploymentArtifacts', - test: () => { - it('should spawn validate, compile and package', () => { - return expect(slsw.hooks['before:package:createDeploymentArtifacts']()).to.be.fulfilled - .then(() => { - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledThrice; - expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly('webpack:validate'); - expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly('webpack:compile'); - expect(slsw.serverless.pluginManager.spawn.thirdCall).to.have.been.calledWithExactly('webpack:package'); - return null; + _.forEach( + [ + { + name: 'before:package:createDeploymentArtifacts', + test: () => { + it('should spawn validate, compile and package', () => { + return expect(slsw.hooks['before:package:createDeploymentArtifacts']()).to.be.fulfilled.then(() => { + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledThrice; + expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly( + 'webpack:validate' + ); + expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly( + 'webpack:compile' + ); + expect(slsw.serverless.pluginManager.spawn.thirdCall).to.have.been.calledWithExactly('webpack:package'); + return null; + }); }); - }); - } - }, - { - name: 'after:package:createDeploymentArtifacts', - test: () => { - it('should call cleanup', () => { - return expect(slsw.hooks['after:package:createDeploymentArtifacts']()).to.be.fulfilled - .then(() => { - expect(slsw.cleanup).to.have.been.calledOnce; - return null; + } + }, + { + name: 'after:package:createDeploymentArtifacts', + test: () => { + it('should call cleanup', () => { + return expect(slsw.hooks['after:package:createDeploymentArtifacts']()).to.be.fulfilled.then(() => { + expect(slsw.cleanup).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'before:deploy:function:packageFunction', - test: () => { - it('should spawn validate, compile and package', () => { - return expect(slsw.hooks['before:deploy:function:packageFunction']()).to.be.fulfilled - .then(() => { - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledThrice; - expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly('webpack:validate'); - expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly('webpack:compile'); - expect(slsw.serverless.pluginManager.spawn.thirdCall).to.have.been.calledWithExactly('webpack:package'); - return null; + } + }, + { + name: 'before:deploy:function:packageFunction', + test: () => { + it('should spawn validate, compile and package', () => { + return expect(slsw.hooks['before:deploy:function:packageFunction']()).to.be.fulfilled.then(() => { + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledThrice; + expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly( + 'webpack:validate' + ); + expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly( + 'webpack:compile' + ); + expect(slsw.serverless.pluginManager.spawn.thirdCall).to.have.been.calledWithExactly('webpack:package'); + return null; + }); }); - }); - } - }, - { - name: 'webpack:webpack', - test: () => { - it('should spawn validate, compile and package', () => { - return expect(slsw.hooks['webpack:webpack']()).to.be.fulfilled - .then(() => { - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledThrice; - expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly('webpack:validate'); - expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly('webpack:compile'); - expect(slsw.serverless.pluginManager.spawn.thirdCall).to.have.been.calledWithExactly('webpack:package'); - return null; + } + }, + { + name: 'webpack:webpack', + test: () => { + it('should spawn validate, compile and package', () => { + return expect(slsw.hooks['webpack:webpack']()).to.be.fulfilled.then(() => { + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledThrice; + expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly( + 'webpack:validate' + ); + expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly( + 'webpack:compile' + ); + expect(slsw.serverless.pluginManager.spawn.thirdCall).to.have.been.calledWithExactly('webpack:package'); + return null; + }); }); - }); - } - }, - { - name: 'before:invoke:local:invoke', - test: () => { - it('should prepare for local invoke', () => { - return expect(slsw.hooks['before:invoke:local:invoke']()).to.be.fulfilled - .then(() => { - expect(ServerlessWebpack.lib.webpack.isLocal).to.be.true; - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledTwice; - expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly('webpack:validate'); - expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly('webpack:compile'); - expect(slsw.prepareLocalInvoke).to.have.been.calledOnce; - return null; + } + }, + { + name: 'before:invoke:local:invoke', + test: () => { + it('should prepare for local invoke', () => { + return expect(slsw.hooks['before:invoke:local:invoke']()).to.be.fulfilled.then(() => { + expect(ServerlessWebpack.lib.webpack.isLocal).to.be.true; + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledTwice; + expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly( + 'webpack:validate' + ); + expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly( + 'webpack:compile' + ); + expect(slsw.prepareLocalInvoke).to.have.been.calledOnce; + return null; + }); }); - }); - it('should skip compile if requested', () => { - slsw.options.build = false; - return expect(slsw.hooks['before:invoke:local:invoke']()).to.be.fulfilled - .then(() => { - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledOnce; - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledWithExactly('webpack:validate'); - expect(slsw.prepareLocalInvoke).to.have.been.calledOnce; - return null; + it('should skip compile if requested', () => { + slsw.options.build = false; + return expect(slsw.hooks['before:invoke:local:invoke']()).to.be.fulfilled.then(() => { + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledOnce; + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledWithExactly('webpack:validate'); + expect(slsw.prepareLocalInvoke).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'after:invoke:local:invoke', - test: () => { - it('should return if watch is disabled', () => { - slsw.options.watch = false; - return expect(slsw.hooks['after:invoke:local:invoke']()).to.be.fulfilled - .then(() => { - expect(slsw.watch).to.not.have.been.called; - return null; + } + }, + { + name: 'after:invoke:local:invoke', + test: () => { + it('should return if watch is disabled', () => { + slsw.options.watch = false; + return expect(slsw.hooks['after:invoke:local:invoke']()).to.be.fulfilled.then(() => { + expect(slsw.watch).to.not.have.been.called; + return null; + }); }); - }); - it('should watch if enabled', () => { - slsw.options.watch = true; - return expect(slsw.hooks['after:invoke:local:invoke']()).to.be.fulfilled - .then(() => { - expect(slsw.watch).to.have.been.calledOnce; - expect(slsw.watch).to.have.been.calledWithExactly('invoke:local'); - return null; + it('should watch if enabled', () => { + slsw.options.watch = true; + return expect(slsw.hooks['after:invoke:local:invoke']()).to.be.fulfilled.then(() => { + expect(slsw.watch).to.have.been.calledOnce; + expect(slsw.watch).to.have.been.calledWithExactly('invoke:local'); + return null; + }); }); - }); - } - }, - { - name: 'before:run:run', - test: () => { - it('should prepare for run', () => { - return expect(slsw.hooks['before:run:run']()).to.be.fulfilled - .then(() => { - expect(slsw.serverless.service.package.individually).to.be.false; - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledTwice; - expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly('webpack:validate'); - expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly('webpack:compile'); - expect(slsw.packExternalModules).to.have.been.calledOnce; - expect(slsw.prepareRun).to.have.been.calledOnce; - return null; + } + }, + { + name: 'before:run:run', + test: () => { + it('should prepare for run', () => { + return expect(slsw.hooks['before:run:run']()).to.be.fulfilled.then(() => { + expect(slsw.serverless.service.package.individually).to.be.false; + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledTwice; + expect(slsw.serverless.pluginManager.spawn.firstCall).to.have.been.calledWithExactly( + 'webpack:validate' + ); + expect(slsw.serverless.pluginManager.spawn.secondCall).to.have.been.calledWithExactly( + 'webpack:compile' + ); + expect(slsw.packExternalModules).to.have.been.calledOnce; + expect(slsw.prepareRun).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'after:run:run', - test: () => { - it('should return if watch is disabled', () => { - slsw.options.watch = false; - return expect(slsw.hooks['after:run:run']()).to.be.fulfilled - .then(() => { - expect(slsw.watch).to.not.have.been.called; - return null; + } + }, + { + name: 'after:run:run', + test: () => { + it('should return if watch is disabled', () => { + slsw.options.watch = false; + return expect(slsw.hooks['after:run:run']()).to.be.fulfilled.then(() => { + expect(slsw.watch).to.not.have.been.called; + return null; + }); }); - }); - it('should watch if enabled', () => { - slsw.options.watch = true; - return expect(slsw.hooks['after:run:run']()).to.be.fulfilled - .then(() => { - expect(slsw.watch).to.have.been.calledOnce; - expect(slsw.watch).to.have.been.calledOnce; - return null; + it('should watch if enabled', () => { + slsw.options.watch = true; + return expect(slsw.hooks['after:run:run']()).to.be.fulfilled.then(() => { + expect(slsw.watch).to.have.been.calledOnce; + expect(slsw.watch).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'webpack:validate:validate', - test: () => { - it('should call validate', () => { - return expect(slsw.hooks['webpack:validate:validate']()).to.be.fulfilled - .then(() => { - expect(slsw.validate).to.have.been.calledOnce; - return null; + } + }, + { + name: 'webpack:validate:validate', + test: () => { + it('should call validate', () => { + return expect(slsw.hooks['webpack:validate:validate']()).to.be.fulfilled.then(() => { + expect(slsw.validate).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'webpack:compile:compile', - test: () => { - it('should call compile', () => { - return expect(slsw.hooks['webpack:compile:compile']()).to.be.fulfilled - .then(() => { - expect(slsw.compile).to.have.been.calledOnce; - return null; + } + }, + { + name: 'webpack:compile:compile', + test: () => { + it('should call compile', () => { + return expect(slsw.hooks['webpack:compile:compile']()).to.be.fulfilled.then(() => { + expect(slsw.compile).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'webpack:compile:watch:compile', - test: () => { - it('should resolve', () => { - return expect(slsw.hooks['webpack:compile:watch:compile']()).to.be.fulfilled; - }); - } - }, - { - name: 'webpack:package:packExternalModules', - test: () => { - it('should call packExternalModules', () => { - return expect(slsw.hooks['webpack:package:packExternalModules']()).to.be.fulfilled - .then(() => { - expect(slsw.packExternalModules).to.have.been.calledOnce; - return null; + } + }, + { + name: 'webpack:compile:watch:compile', + test: () => { + it('should resolve', () => { + return expect(slsw.hooks['webpack:compile:watch:compile']()).to.be.fulfilled; }); - }); - } - }, - { - name: 'webpack:package:packageModules', - test: () => { - it('should call packageModules', () => { - return expect(slsw.hooks['webpack:package:packageModules']()).to.be.fulfilled - .then(() => { - expect(slsw.packageModules).to.have.been.calledOnce; - return null; + } + }, + { + name: 'webpack:package:packExternalModules', + test: () => { + it('should call packExternalModules', () => { + return expect(slsw.hooks['webpack:package:packExternalModules']()).to.be.fulfilled.then(() => { + expect(slsw.packExternalModules).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'before:offline:start', - test: () => { - it('should prepare offline', () => { - return expect(slsw.hooks['before:offline:start']()).to.be.fulfilled - .then(() => { - expect(ServerlessWebpack.lib.webpack.isLocal).to.be.true; - expect(slsw.prepareOfflineInvoke).to.have.been.calledOnce; - expect(slsw.wpwatch).to.have.been.calledOnce; - return null; + } + }, + { + name: 'webpack:package:packageModules', + test: () => { + it('should call packageModules', () => { + return expect(slsw.hooks['webpack:package:packageModules']()).to.be.fulfilled.then(() => { + expect(slsw.packageModules).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'before:offline:start:init', - test: () => { - it('should prepare offline', () => { - return expect(slsw.hooks['before:offline:start:init']()).to.be.fulfilled - .then(() => { - expect(ServerlessWebpack.lib.webpack.isLocal).to.be.true; - expect(slsw.prepareOfflineInvoke).to.have.been.calledOnce; - expect(slsw.wpwatch).to.have.been.calledOnce; - return null; + } + }, + { + name: 'before:offline:start', + test: () => { + it('should prepare offline', () => { + return expect(slsw.hooks['before:offline:start']()).to.be.fulfilled.then(() => { + expect(ServerlessWebpack.lib.webpack.isLocal).to.be.true; + expect(slsw.prepareOfflineInvoke).to.have.been.calledOnce; + expect(slsw.wpwatch).to.have.been.calledOnce; + return null; + }); }); - }); - } - }, - { - name: 'before:step-functions-offline:start', - test: () => { - it('should prepare offline', () => { - return expect(slsw.hooks['before:step-functions-offline:start']()).to.be.fulfilled - .then(() => { - expect(ServerlessWebpack.lib.webpack.isLocal).to.be.true; - expect(slsw.prepareStepOfflineInvoke).to.have.been.calledOnce; - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledOnce; - expect(slsw.serverless.pluginManager.spawn).to.have.been.calledWithExactly('webpack:compile'); - return null; + } + }, + { + name: 'before:offline:start:init', + test: () => { + it('should prepare offline', () => { + return expect(slsw.hooks['before:offline:start:init']()).to.be.fulfilled.then(() => { + expect(ServerlessWebpack.lib.webpack.isLocal).to.be.true; + expect(slsw.prepareOfflineInvoke).to.have.been.calledOnce; + expect(slsw.wpwatch).to.have.been.calledOnce; + return null; + }); + }); + } + }, + { + name: 'before:step-functions-offline:start', + test: () => { + it('should prepare offline', () => { + return expect(slsw.hooks['before:step-functions-offline:start']()).to.be.fulfilled.then(() => { + expect(ServerlessWebpack.lib.webpack.isLocal).to.be.true; + expect(slsw.prepareStepOfflineInvoke).to.have.been.calledOnce; + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledOnce; + expect(slsw.serverless.pluginManager.spawn).to.have.been.calledWithExactly('webpack:compile'); + return null; + }); }); - }); + } } - }, - ], hook => { - it(`should expose hook ${hook.name}`, () => { - expect(slsw).to.have.a.nested.property(`hooks.${hook.name}`); - }); - - describe(hook.name, () => { - hook.test(); - }); - }); + ], + hook => { + it(`should expose hook ${hook.name}`, () => { + expect(slsw).to.have.a.nested.property(`hooks.${hook.name}`); + }); + + describe(hook.name, () => { + hook.test(); + }); + } + ); }); }); diff --git a/lib/Configuration.js b/lib/Configuration.js index 705385c33..a3fde813e 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -18,9 +18,7 @@ const DefaultConfig = { }; class Configuration { - constructor(custom) { - this._config = {}; this._hasLegacyConfig = false; @@ -80,4 +78,4 @@ class Configuration { } } -module.exports = Configuration; \ No newline at end of file +module.exports = Configuration; diff --git a/lib/Configuration.test.js b/lib/Configuration.test.js index 6d61bdbac..60206602b 100644 --- a/lib/Configuration.test.js +++ b/lib/Configuration.test.js @@ -25,13 +25,17 @@ describe('Configuration', () => { it('should set default configuration without custom', () => { const config = new Configuration(); - expect(config).to.have.a.property('_config').that.deep.equals(expectedDefaults); + expect(config) + .to.have.a.property('_config') + .that.deep.equals(expectedDefaults); expect(config).to.have.a.property('hasLegacyConfig').that.is.false; }); it('should set default configuration without webpack property', () => { const config = new Configuration({}); - expect(config).to.have.a.property('_config').that.deep.equals(expectedDefaults); + expect(config) + .to.have.a.property('_config') + .that.deep.equals(expectedDefaults); expect(config).to.have.a.property('hasLegacyConfig').that.is.false; }); }); @@ -40,13 +44,17 @@ describe('Configuration', () => { it('should use custom.webpackIncludeModules', () => { const testCustom = { webpackIncludeModules: { forceInclude: ['mod1'] } }; const config = new Configuration(testCustom); - expect(config).to.have.a.property('includeModules').that.deep.equals(testCustom.webpackIncludeModules); + expect(config) + .to.have.a.property('includeModules') + .that.deep.equals(testCustom.webpackIncludeModules); }); it('should use custom.webpack as string', () => { const testCustom = { webpack: 'myWebpackFile.js' }; const config = new Configuration(testCustom); - expect(config).to.have.a.property('webpackConfig').that.equals('myWebpackFile.js'); + expect(config) + .to.have.a.property('webpackConfig') + .that.equals('myWebpackFile.js'); }); it('should detect it', () => { @@ -56,12 +64,14 @@ describe('Configuration', () => { }); it('should add defaults', () => { - const testCustom = { + const testCustom = { webpackIncludeModules: { forceInclude: ['mod1'] }, webpack: 'myWebpackFile.js' }; const config = new Configuration(testCustom); - expect(config).to.have.a.property('includeModules').that.deep.equals(testCustom.webpackIncludeModules); + expect(config) + .to.have.a.property('includeModules') + .that.deep.equals(testCustom.webpackIncludeModules); expect(config._config).to.deep.equal({ webpackConfig: 'myWebpackFile.js', includeModules: { forceInclude: ['mod1'] }, diff --git a/lib/cleanup.js b/lib/cleanup.js index ef34a966d..63bfcc796 100644 --- a/lib/cleanup.js +++ b/lib/cleanup.js @@ -18,5 +18,5 @@ module.exports = { } return BbPromise.resolve(); - }, + } }; diff --git a/lib/compile.js b/lib/compile.js index cc0a56483..e5c2363cf 100644 --- a/lib/compile.js +++ b/lib/compile.js @@ -11,40 +11,38 @@ module.exports = { const compiler = webpack(this.webpackConfig); - return BbPromise - .fromCallback(cb => compiler.run(cb)) - .then(stats => { - - if (!this.multiCompile) { - stats = { stats: [stats] }; + return BbPromise.fromCallback(cb => compiler.run(cb)).then(stats => { + if (!this.multiCompile) { + stats = { stats: [stats] }; + } + + const compileOutputPaths = []; + const consoleStats = this.webpackConfig.stats || + _.get(this, 'webpackConfig[0].stats') || { + colors: tty.isatty(process.stdout.fd), + hash: false, + version: false, + chunks: false, + children: false + }; + + _.forEach(stats.stats, compileStats => { + const statsOutput = compileStats.toString(consoleStats); + if (statsOutput) { + this.serverless.cli.consoleLog(statsOutput); } - const compileOutputPaths = []; - const consoleStats = this.webpackConfig.stats || _.get(this, 'webpackConfig[0].stats') || { - colors: tty.isatty(process.stdout.fd), - hash: false, - version: false, - chunks: false, - children: false - }; - - _.forEach(stats.stats, compileStats => { - const statsOutput = compileStats.toString(consoleStats); - if (statsOutput) { - this.serverless.cli.consoleLog(statsOutput); - } - - if (compileStats.compilation.errors.length) { - throw new Error('Webpack compilation error, see above'); - } + if (compileStats.compilation.errors.length) { + throw new Error('Webpack compilation error, see above'); + } - compileOutputPaths.push(compileStats.compilation.compiler.outputPath); - }); + compileOutputPaths.push(compileStats.compilation.compiler.outputPath); + }); - this.compileOutputPaths = compileOutputPaths; - this.compileStats = stats; + this.compileOutputPaths = compileOutputPaths; + this.compileStats = stats; - return BbPromise.resolve(); - }); - }, + return BbPromise.resolve(); + }); + } }; diff --git a/lib/packExternalModules.js b/lib/packExternalModules.js index 0c7ab2f98..4761d9614 100644 --- a/lib/packExternalModules.js +++ b/lib/packExternalModules.js @@ -11,7 +11,11 @@ const Packagers = require('./packagers'); function rebaseFileReferences(pathToPackageRoot, moduleVersion) { if (/^(?:file:[^/]{2}|\.\/|\.\.\/)/.test(moduleVersion)) { const filePath = _.replace(moduleVersion, /^file:/, ''); - return _.replace(`${_.startsWith(moduleVersion, 'file:') ? 'file:' : ''}${pathToPackageRoot}/${filePath}`, /\\/g, '/'); + return _.replace( + `${_.startsWith(moduleVersion, 'file:') ? 'file:' : ''}${pathToPackageRoot}/${filePath}`, + /\\/g, + '/' + ); } return moduleVersion; @@ -41,7 +45,8 @@ function addModulesToPackageJson(externalModules, packageJson, pathToPackageRoot * @this - The active plugin instance */ function removeExcludedModules(modules, packageForceExcludes, log) { - const excludedModules = _.remove(modules, externalModule => { // eslint-disable-line lodash/prefer-immutable-method + // eslint-disable-next-line lodash/prefer-immutable-method + const excludedModules = _.remove(modules, externalModule => { const splitModule = _.split(externalModule, '@'); // If we have a scoped module we have to re-add the @ if (_.startsWith(externalModule, '@')) { @@ -89,7 +94,13 @@ function getProdModules(externalModules, packagePath, dependencyGraph, forceExcl const peerDependencies = require(modulePackagePath).peerDependencies; if (!_.isEmpty(peerDependencies)) { this.options.verbose && this.serverless.cli.log(`Adding explicit peers for dependency ${module.external}`); - const peerModules = getProdModules.call(this, _.map(peerDependencies, (value, key) => ({ external: key })), packagePath, dependencyGraph, forceExcludes); + const peerModules = getProdModules.call( + this, + _.map(peerDependencies, (value, key) => ({ external: key })), + packagePath, + dependencyGraph, + forceExcludes + ); Array.prototype.push.apply(prodModules, peerModules); } } catch (e) { @@ -104,18 +115,31 @@ function getProdModules(externalModules, packagePath, dependencyGraph, forceExcl this.serverless.cli.log(`WARNING: Could not determine version of module ${module.external}`); } prodModules.push(moduleVersion ? `${module.external}@${moduleVersion}` : module.external); - } else if (packageJson.devDependencies && packageJson.devDependencies[module.external] && !_.includes(forceExcludes, module.external)) { + } else if ( + packageJson.devDependencies && + packageJson.devDependencies[module.external] && + !_.includes(forceExcludes, module.external) + ) { // To minimize the chance of breaking setups we whitelist packages available on AWS here. These are due to the previously missing check // most likely set in devDependencies and should not lead to an error now. const ignoredDevDependencies = ['aws-sdk']; if (!_.includes(ignoredDevDependencies, module.external)) { // Runtime dependency found in devDependencies but not forcefully excluded - this.serverless.cli.log(`ERROR: Runtime dependency '${module.external}' found in devDependencies. Move it to dependencies or use forceExclude to explicitly exclude it.`); + this.serverless.cli.log( + `ERROR: Runtime dependency '${ + module.external + }' found in devDependencies. Move it to dependencies or use forceExclude to explicitly exclude it.` + ); throw new this.serverless.classes.Error(`Serverless-webpack dependency error: ${module.external}.`); } - this.options.verbose && this.serverless.cli.log(`INFO: Runtime dependency '${module.external}' found in devDependencies. It has been excluded automatically.`); + this.options.verbose && + this.serverless.cli.log( + `INFO: Runtime dependency '${ + module.external + }' found in devDependencies. It has been excluded automatically.` + ); } } }); @@ -190,7 +214,6 @@ module.exports = { * and performance. */ packExternalModules() { - const stats = this.compileStats; const includes = this.configuration.includeModules; @@ -204,153 +227,204 @@ module.exports = { const packageForceExcludes = _.get(includes, 'forceExclude', []); const packagePath = includes.packagePath || './package.json'; const packageJsonPath = path.join(process.cwd(), packagePath); - const packageScripts = _.reduce(this.configuration.packagerOptions.scripts || [], (__, script, index) => { - __[`script${index}`] = script; - return __; - }, {}); + const packageScripts = _.reduce( + this.configuration.packagerOptions.scripts || [], + (__, script, index) => { + __[`script${index}`] = script; + return __; + }, + {} + ); // Determine and create packager - return BbPromise.try(() => Packagers.get.call(this, this.configuration.packager)) - .then(packager => { - // Fetch needed original package.json sections - const sectionNames = packager.copyPackageSectionNames; - const packageJson = this.serverless.utils.readFileSync(packageJsonPath); - const packageSections = _.pick(packageJson, sectionNames); - if (!_.isEmpty(packageSections)) { - this.options.verbose && this.serverless.cli.log(`Using package.json sections ${_.join(_.keys(packageSections), ', ')}`); + return BbPromise.try(() => Packagers.get.call(this, this.configuration.packager)).then(packager => { + // Fetch needed original package.json sections + const sectionNames = packager.copyPackageSectionNames; + const packageJson = this.serverless.utils.readFileSync(packageJsonPath); + const packageSections = _.pick(packageJson, sectionNames); + if (!_.isEmpty(packageSections)) { + this.options.verbose && + this.serverless.cli.log(`Using package.json sections ${_.join(_.keys(packageSections), ', ')}`); + } + + // Get first level dependency graph + this.options.verbose && this.serverless.cli.log(`Fetch dependency graph from ${packageJsonPath}`); + + return packager.getProdDependencies(path.dirname(packageJsonPath), 1).then(dependencyGraph => { + const problems = _.get(dependencyGraph, 'problems', []); + if (this.options.verbose && !_.isEmpty(problems)) { + this.serverless.cli.log(`Ignoring ${_.size(problems)} NPM errors:`); + _.forEach(problems, problem => { + this.serverless.cli.log(`=> ${problem}`); + }); } - // Get first level dependency graph - this.options.verbose && this.serverless.cli.log(`Fetch dependency graph from ${packageJsonPath}`); + // (1) Generate dependency composition + const compositeModules = _.uniq( + _.flatMap(stats.stats, compileStats => { + const externalModules = _.concat( + getExternalModules.call(this, compileStats), + _.map(packageForceIncludes, whitelistedPackage => ({ + external: whitelistedPackage + })) + ); + return getProdModules.call(this, externalModules, packagePath, dependencyGraph, packageForceExcludes); + }) + ); + removeExcludedModules.call(this, compositeModules, packageForceExcludes, true); - return packager.getProdDependencies(path.dirname(packageJsonPath), 1) - .then(dependencyGraph => { - const problems = _.get(dependencyGraph, 'problems', []); - if (this.options.verbose && !_.isEmpty(problems)) { - this.serverless.cli.log(`Ignoring ${_.size(problems)} NPM errors:`); - _.forEach(problems, problem => { - this.serverless.cli.log(`=> ${problem}`); - }); - } + if (_.isEmpty(compositeModules)) { + // The compiled code does not reference any external modules at all + this.serverless.cli.log('No external modules needed'); + return BbPromise.resolve(); + } + + // (1.a) Install all needed modules + const compositeModulePath = path.join(this.webpackOutputPath, 'dependencies'); + const compositePackageJson = path.join(compositeModulePath, 'package.json'); + + // (1.a.1) Create a package.json + const compositePackage = _.defaults( + { + name: this.serverless.service.service, + version: '1.0.0', + description: `Packaged externals for ${this.serverless.service.service}`, + private: true, + scripts: packageScripts + }, + packageSections + ); + const relPath = path.relative(compositeModulePath, path.dirname(packageJsonPath)); + addModulesToPackageJson(compositeModules, compositePackage, relPath); + this.serverless.utils.writeFileSync(compositePackageJson, JSON.stringify(compositePackage, null, 2)); + + // (1.a.2) Copy package-lock.json if it exists, to prevent unwanted upgrades + const packageLockPath = path.join(path.dirname(packageJsonPath), packager.lockfileName); + let hasPackageLock = false; + return BbPromise.fromCallback(cb => fse.pathExists(packageLockPath, cb)) + .then(exists => { + if (exists) { + this.serverless.cli.log('Package lock found - Using locked versions'); + try { + let packageLockFile = this.serverless.utils.readFileSync(packageLockPath); + packageLockFile = packager.rebaseLockfile(relPath, packageLockFile); + if (_.isObject(packageLockFile)) { + packageLockFile = JSON.stringify(packageLockFile, null, 2); + } - // (1) Generate dependency composition - const compositeModules = _.uniq(_.flatMap(stats.stats, compileStats => { - const externalModules = _.concat( + this.serverless.utils.writeFileSync( + path.join(compositeModulePath, packager.lockfileName), + packageLockFile + ); + hasPackageLock = true; + } catch (err) { + this.serverless.cli.log(`Warning: Could not read lock file: ${err.message}`); + } + } + return BbPromise.resolve(); + }) + .then(() => { + const start = _.now(); + this.serverless.cli.log('Packing external modules: ' + compositeModules.join(', ')); + return packager + .install(compositeModulePath, this.configuration.packagerOptions) + .then(() => this.options.verbose && this.serverless.cli.log(`Package took [${_.now() - start} ms]`)) + .return(stats.stats); + }) + .mapSeries(compileStats => { + const modulePath = compileStats.compilation.compiler.outputPath; + + // Create package.json + const modulePackageJson = path.join(modulePath, 'package.json'); + const modulePackage = _.defaults( + { + name: this.serverless.service.service, + version: '1.0.0', + description: `Packaged externals for ${this.serverless.service.service}`, + private: true, + scripts: packageScripts, + dependencies: {} + }, + packageSections + ); + const prodModules = getProdModules.call( + this, + _.concat( getExternalModules.call(this, compileStats), - _.map(packageForceIncludes, whitelistedPackage => ({ external: whitelistedPackage })) - ); - return getProdModules.call(this, externalModules, packagePath, dependencyGraph, packageForceExcludes); - })); - removeExcludedModules.call(this, compositeModules, packageForceExcludes, true); - - if (_.isEmpty(compositeModules)) { - // The compiled code does not reference any external modules at all - this.serverless.cli.log('No external modules needed'); + _.map(packageForceIncludes, whitelistedPackage => ({ + external: whitelistedPackage + })) + ), + packagePath, + dependencyGraph, + packageForceExcludes + ); + removeExcludedModules.call(this, prodModules, packageForceExcludes); + const relPath = path.relative(modulePath, path.dirname(packageJsonPath)); + addModulesToPackageJson(prodModules, modulePackage, relPath); + this.serverless.utils.writeFileSync(modulePackageJson, JSON.stringify(modulePackage, null, 2)); + + // GOOGLE: Copy modules only if not google-cloud-functions + // GCF Auto installs the package json + if (_.get(this.serverless, 'service.provider.name') === 'google') { return BbPromise.resolve(); } - // (1.a) Install all needed modules - const compositeModulePath = path.join(this.webpackOutputPath, 'dependencies'); - const compositePackageJson = path.join(compositeModulePath, 'package.json'); - - // (1.a.1) Create a package.json - const compositePackage = _.defaults({ - name: this.serverless.service.service, - version: '1.0.0', - description: `Packaged externals for ${this.serverless.service.service}`, - private: true, - scripts: packageScripts - }, packageSections); - const relPath = path.relative(compositeModulePath, path.dirname(packageJsonPath)); - addModulesToPackageJson(compositeModules, compositePackage, relPath); - this.serverless.utils.writeFileSync(compositePackageJson, JSON.stringify(compositePackage, null, 2)); - - // (1.a.2) Copy package-lock.json if it exists, to prevent unwanted upgrades - const packageLockPath = path.join(path.dirname(packageJsonPath), packager.lockfileName); - let hasPackageLock = false; - return BbPromise.fromCallback(cb => fse.pathExists(packageLockPath, cb)) - .then(exists => { - if (exists) { - this.serverless.cli.log('Package lock found - Using locked versions'); - try { - let packageLockFile = this.serverless.utils.readFileSync(packageLockPath); - packageLockFile = packager.rebaseLockfile(relPath, packageLockFile); - if (_.isObject(packageLockFile)) { - packageLockFile = JSON.stringify(packageLockFile, null, 2); - } - - this.serverless.utils.writeFileSync(path.join(compositeModulePath, packager.lockfileName), packageLockFile); - hasPackageLock = true; - } catch (err) { - this.serverless.cli.log(`Warning: Could not read lock file: ${err.message}`); - } - } - return BbPromise.resolve(); - }) - .then(() => { - const start = _.now(); - this.serverless.cli.log('Packing external modules: ' + compositeModules.join(', ')); - return packager.install(compositeModulePath, this.configuration.packagerOptions) - .then(() => this.options.verbose && this.serverless.cli.log(`Package took [${_.now() - start} ms]`)) - .return(stats.stats); - }) - .mapSeries(compileStats => { - const modulePath = compileStats.compilation.compiler.outputPath; - - // Create package.json - const modulePackageJson = path.join(modulePath, 'package.json'); - const modulePackage = _.defaults({ - name: this.serverless.service.service, - version: '1.0.0', - description: `Packaged externals for ${this.serverless.service.service}`, - private: true, - scripts: packageScripts, - dependencies: {} - }, packageSections); - const prodModules = getProdModules.call(this, - _.concat( - getExternalModules.call(this, compileStats), - _.map(packageForceIncludes, whitelistedPackage => ({ external: whitelistedPackage })) - ), packagePath, dependencyGraph, packageForceExcludes); - removeExcludedModules.call(this, prodModules, packageForceExcludes); - const relPath = path.relative(modulePath, path.dirname(packageJsonPath)); - addModulesToPackageJson(prodModules, modulePackage, relPath); - this.serverless.utils.writeFileSync(modulePackageJson, JSON.stringify(modulePackage, null, 2)); - - // GOOGLE: Copy modules only if not google-cloud-functions - // GCF Auto installs the package json - if (_.get(this.serverless, 'service.provider.name') === 'google') { - return BbPromise.resolve(); - } - - const startCopy = _.now(); - return BbPromise.try(() => { - // Only copy dependency modules if demanded by packager - if (packager.mustCopyModules) { - return BbPromise.fromCallback(callback => fse.copy(path.join(compositeModulePath, 'node_modules'), path.join(modulePath, 'node_modules'), callback)); - } - return BbPromise.resolve(); - }) - .then(() => hasPackageLock ? - BbPromise.fromCallback(callback => fse.copy(path.join(compositeModulePath, packager.lockfileName), path.join(modulePath, packager.lockfileName), callback)) : - BbPromise.resolve() + const startCopy = _.now(); + return BbPromise.try(() => { + // Only copy dependency modules if demanded by packager + if (packager.mustCopyModules) { + return BbPromise.fromCallback(callback => + fse.copy( + path.join(compositeModulePath, 'node_modules'), + path.join(modulePath, 'node_modules'), + callback ) - .tap(() => this.options.verbose && this.serverless.cli.log(`Copy modules: ${modulePath} [${_.now() - startCopy} ms]`)) - .then(() => { - // Prune extraneous packages - removes not needed ones - const startPrune = _.now(); - return packager.prune(modulePath, this.configuration.packagerOptions) - .tap(() => this.options.verbose && this.serverless.cli.log(`Prune: ${modulePath} [${_.now() - startPrune} ms]`)); - }) - .then(() => { - // Prune extraneous packages - removes not needed ones - const startRunScripts = _.now(); - return packager.runScripts(modulePath, _.keys(packageScripts)) - .tap(() => this.options.verbose && this.serverless.cli.log(`Run scripts: ${modulePath} [${_.now() - startRunScripts} ms]`)); - }); + ); + } + return BbPromise.resolve(); + }) + .then(() => + hasPackageLock + ? BbPromise.fromCallback(callback => + fse.copy( + path.join(compositeModulePath, packager.lockfileName), + path.join(modulePath, packager.lockfileName), + callback + ) + ) + : BbPromise.resolve() + ) + .tap( + () => + this.options.verbose && + this.serverless.cli.log(`Copy modules: ${modulePath} [${_.now() - startCopy} ms]`) + ) + .then(() => { + // Prune extraneous packages - removes not needed ones + const startPrune = _.now(); + return packager + .prune(modulePath, this.configuration.packagerOptions) + .tap( + () => + this.options.verbose && + this.serverless.cli.log(`Prune: ${modulePath} [${_.now() - startPrune} ms]`) + ); }) - .return(); - }); + .then(() => { + // Prune extraneous packages - removes not needed ones + const startRunScripts = _.now(); + return packager + .runScripts(modulePath, _.keys(packageScripts)) + .tap( + () => + this.options.verbose && + this.serverless.cli.log(`Run scripts: ${modulePath} [${_.now() - startRunScripts} ms]`) + ); + }); + }) + .return(); }); + }); } }; diff --git a/lib/packageModules.js b/lib/packageModules.js index dc21c7729..422af3893 100644 --- a/lib/packageModules.js +++ b/lib/packageModules.js @@ -18,7 +18,7 @@ function setArtifactPath(funcName, func, artifactPath) { this.serverless.cli.log(`${funcName} is packaged by the webpack plugin. Ignore messages from SLS.`); } else { func.package = { - artifact: artifactPath, + artifact: artifactPath }; } } @@ -26,10 +26,7 @@ function setArtifactPath(funcName, func, artifactPath) { function zip(directory, name) { const zip = archiver.create('zip'); // Create artifact in temp path and move it to the package path (if any) later - const artifactFilePath = path.join(this.serverless.config.servicePath, - '.serverless', - name - ); + const artifactFilePath = path.join(this.serverless.config.servicePath, '.serverless', name); this.serverless.utils.writeFileDir(artifactFilePath); const output = fs.createWriteStream(artifactFilePath); @@ -38,12 +35,11 @@ function zip(directory, name) { cwd: directory, dot: true, silent: true, - follow: true, + follow: true }); if (_.isEmpty(files)) { - const error = new this.serverless - .classes.Error('Packaging: No files found'); + const error = new this.serverless.classes.Error('Packaging: No files found'); return BbPromise.reject(error); } @@ -51,10 +47,7 @@ function zip(directory, name) { zip.pipe(output); _.forEach(files, filePath => { - const fullPath = path.resolve( - directory, - filePath - ); + const fullPath = path.resolve(directory, filePath); const stats = fs.statSync(fullPath); @@ -62,7 +55,7 @@ function zip(directory, name) { zip.append(fs.readFileSync(fullPath), { name: filePath, mode: stats.mode, - date: new Date(0), // necessary to get the same hash when zipping the same content + date: new Date(0) // necessary to get the same hash when zipping the same content }); } }); @@ -72,7 +65,7 @@ function zip(directory, name) { return new BbPromise((resolve, reject) => { output.on('close', () => resolve(artifactFilePath)); - zip.on('error', (err) => reject(err)); + zip.on('error', err => reject(err)); }); } @@ -86,17 +79,27 @@ module.exports = { const modulePath = compileStats.compilation.compiler.outputPath; const startZip = _.now(); - return zip.call(this, modulePath, filename) - .tap(() => this.options.verbose && - this.serverless.cli.log(`Zip ${_.isEmpty(entryFunction) ? 'service' : 'function'}: ${modulePath} [${_.now() - startZip} ms]`)) - .then(artifactPath => { - if (_.get(this.serverless, 'service.package.individually')) { - setArtifactPath.call(this, entryFunction.funcName, entryFunction.func, path.relative(this.serverless.config.servicePath, artifactPath)); - } - return artifactPath; - }); - }) - .then(artifacts => { + return zip + .call(this, modulePath, filename) + .tap( + () => + this.options.verbose && + this.serverless.cli.log( + `Zip ${_.isEmpty(entryFunction) ? 'service' : 'function'}: ${modulePath} [${_.now() - startZip} ms]` + ) + ) + .then(artifactPath => { + if (_.get(this.serverless, 'service.package.individually')) { + setArtifactPath.call( + this, + entryFunction.funcName, + entryFunction.func, + path.relative(this.serverless.config.servicePath, artifactPath) + ); + } + return artifactPath; + }); + }).then(artifacts => { if (!_.get(this.serverless, 'service.package.individually') && !_.isEmpty(artifacts)) { // Set the service artifact to all functions const allFunctionNames = this.serverless.service.getAllFunctions(); @@ -106,7 +109,11 @@ module.exports = { }); // For Google set the service artifact path if (_.get(this.serverless, 'service.provider.name') === 'google') { - _.set(this.serverless, 'service.package.artifact', path.relative(this.serverless.config.servicePath, artifacts[0])); + _.set( + this.serverless, + 'service.package.artifact', + path.relative(this.serverless.config.servicePath, artifacts[0]) + ); } } diff --git a/lib/packagers/index.js b/lib/packagers/index.js index ff0212580..910656631 100644 --- a/lib/packagers/index.js +++ b/lib/packagers/index.js @@ -1,11 +1,11 @@ 'use strict'; /** * Factory for supported packagers. - * + * * All packagers must implement the following interface: - * + * * interface Packager { - * + * * static get lockfileName(): string; * static get copyPackageSectionNames(): Array; * static get mustCopyModules(): boolean; @@ -14,7 +14,7 @@ * static install(cwd: string): BbPromise; * static prune(cwd: string): BbPromise; * static runScripts(cwd: string, scriptNames): BbPromise; - * + * * } */ diff --git a/lib/packagers/index.test.js b/lib/packagers/index.test.js index 2e77a4359..e3ec7a38e 100644 --- a/lib/packagers/index.test.js +++ b/lib/packagers/index.test.js @@ -49,12 +49,15 @@ describe('packagers factory', () => { consoleLog: sandbox.stub() }; - module = _.assign({ - serverless, - options: { - verbose: true + module = _.assign( + { + serverless, + options: { + verbose: true + } }, - }, baseModule); + baseModule + ); }); afterEach(() => { diff --git a/lib/packagers/npm.js b/lib/packagers/npm.js index 8cb0393c1..a15deca72 100644 --- a/lib/packagers/npm.js +++ b/lib/packagers/npm.js @@ -8,7 +8,8 @@ const BbPromise = require('bluebird'); const Utils = require('../utils'); class NPM { - static get lockfileName() { // eslint-disable-line lodash/prefer-constant + // eslint-disable-next-line lodash/prefer-constant + static get lockfileName() { return 'package-lock.json'; } @@ -16,7 +17,8 @@ class NPM { return []; } - static get mustCopyModules() { // eslint-disable-line lodash/prefer-constant + // eslint-disable-next-line lodash/prefer-constant + static get mustCopyModules() { return true; } @@ -25,7 +27,7 @@ class NPM { const command = /^win/.test(process.platform) ? 'npm.cmd' : 'npm'; const args = [ 'ls', - '-prod', // Only prod dependencies + '-prod', // Only prod dependencies '-json', `-depth=${depth || 1}` ]; @@ -33,32 +35,39 @@ class NPM { const ignoredNpmErrors = [ { npmError: 'extraneous', log: false }, { npmError: 'missing', log: false }, - { npmError: 'peer dep missing', log: true }, + { npmError: 'peer dep missing', log: true } ]; return Utils.spawnProcess(command, args, { cwd: cwd }) - .catch(err => { - if (err instanceof Utils.SpawnError) { - // Only exit with an error if we have critical npm errors for 2nd level inside - const errors = _.split(err.stderr, '\n'); - const failed = _.reduce(errors, (failed, error) => { - if (failed) { - return true; + .catch(err => { + if (err instanceof Utils.SpawnError) { + // Only exit with an error if we have critical npm errors for 2nd level inside + const errors = _.split(err.stderr, '\n'); + const failed = _.reduce( + errors, + (failed, error) => { + if (failed) { + return true; + } + return ( + !_.isEmpty(error) && + !_.some(ignoredNpmErrors, ignoredError => _.startsWith(error, `npm ERR! ${ignoredError.npmError}`)) + ); + }, + false + ); + + if (!failed && !_.isEmpty(err.stdout)) { + return BbPromise.resolve({ stdout: err.stdout }); } - return !_.isEmpty(error) && !_.some(ignoredNpmErrors, ignoredError => _.startsWith(error, `npm ERR! ${ignoredError.npmError}`)); - }, false); - - if (!failed && !_.isEmpty(err.stdout)) { - return BbPromise.resolve({ stdout: err.stdout }); } - } - return BbPromise.reject(err); - }) - .then(processOutput => processOutput.stdout) - .then(depJson => BbPromise.try(() => JSON.parse(depJson))); + return BbPromise.reject(err); + }) + .then(processOutput => processOutput.stdout) + .then(depJson => BbPromise.try(() => JSON.parse(depJson))); } static _rebaseFileReferences(pathToPackageRoot, moduleVersion) { @@ -66,14 +75,14 @@ class NPM { const filePath = _.replace(moduleVersion, /^file:/, ''); return _.replace(`file:${pathToPackageRoot}/${filePath}`, /\\/g, '/'); } - + return moduleVersion; } - + /** * We should not be modifying 'package-lock.json' * because this file should be treated as internal to npm. - * + * * Rebase package-lock is a temporary workaround and must be * removed as soon as https://github.com/npm/npm/issues/19183 gets fixed. */ @@ -81,7 +90,7 @@ class NPM { if (lockfile.version) { lockfile.version = NPM._rebaseFileReferences(pathToPackageRoot, lockfile.version); } - + if (lockfile.dependencies) { _.forIn(lockfile.dependencies, lockedDependency => { NPM.rebaseLockfile(pathToPackageRoot, lockedDependency); @@ -90,34 +99,28 @@ class NPM { return lockfile; } - + static install(cwd) { const command = /^win/.test(process.platform) ? 'npm.cmd' : 'npm'; const args = ['install']; - return Utils.spawnProcess(command, args, { cwd }) - .return(); + return Utils.spawnProcess(command, args, { cwd }).return(); } static prune(cwd) { const command = /^win/.test(process.platform) ? 'npm.cmd' : 'npm'; const args = ['prune']; - return Utils.spawnProcess(command, args, { cwd }) - .return(); + return Utils.spawnProcess(command, args, { cwd }).return(); } static runScripts(cwd, scriptNames) { const command = /^win/.test(process.platform) ? 'npm.cmd' : 'npm'; return BbPromise.mapSeries(scriptNames, scriptName => { - const args = [ - 'run', - scriptName - ]; - + const args = [ 'run', scriptName ]; + return Utils.spawnProcess(command, args, { cwd }); - }) - .return(); + }).return(); } } diff --git a/lib/packagers/npm.test.js b/lib/packagers/npm.test.js index 0feaa86c8..890da384d 100644 --- a/lib/packagers/npm.test.js +++ b/lib/packagers/npm.test.js @@ -49,17 +49,12 @@ describe('npm', () => { describe('install', () => { it('should use npm install', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: 'installed successfully', stderr: '' })); - return expect(npmModule.install('myPath')).to.be.fulfilled - .then(result => { + return expect(npmModule.install('myPath')).to.be.fulfilled.then(result => { expect(result).to.be.undefined; expect(Utils.spawnProcess).to.have.been.calledOnce; - expect(Utils.spawnProcess).to.have.been.calledWithExactly( - sinon.match(/^npm/), - ['install'], - { - cwd: 'myPath' - } - ); + expect(Utils.spawnProcess).to.have.been.calledWithExactly(sinon.match(/^npm/), ['install'], { + cwd: 'myPath' + }); return null; }); }); @@ -68,17 +63,12 @@ describe('npm', () => { describe('prune', () => { it('should use npm prune', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: 'success', stderr: '' })); - return expect(npmModule.prune('myPath')).to.be.fulfilled - .then(result => { + return expect(npmModule.prune('myPath')).to.be.fulfilled.then(result => { expect(result).to.be.undefined; expect(Utils.spawnProcess).to.have.been.calledOnce; - expect(Utils.spawnProcess).to.have.been.calledWithExactly( - sinon.match(/^npm/), - ['prune'], - { - cwd: 'myPath' - } - ); + expect(Utils.spawnProcess).to.have.been.calledWithExactly(sinon.match(/^npm/), ['prune'], { + cwd: 'myPath' + }); return null; }); }); @@ -87,24 +77,15 @@ describe('npm', () => { describe('runScripts', () => { it('should use npm run for the given scripts', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: 'success', stderr: '' })); - return expect(npmModule.runScripts('myPath', [ 's1', 's2' ])).to.be.fulfilled - .then(result => { + return expect(npmModule.runScripts('myPath', [ 's1', 's2' ])).to.be.fulfilled.then(result => { expect(result).to.be.undefined; expect(Utils.spawnProcess).to.have.been.calledTwice; - expect(Utils.spawnProcess.firstCall).to.have.been.calledWithExactly( - sinon.match(/^npm/), - [ 'run', 's1' ], - { - cwd: 'myPath' - } - ); - expect(Utils.spawnProcess.secondCall).to.have.been.calledWithExactly( - sinon.match(/^npm/), - [ 'run', 's2' ], - { - cwd: 'myPath' - } - ); + expect(Utils.spawnProcess.firstCall).to.have.been.calledWithExactly(sinon.match(/^npm/), [ 'run', 's1' ], { + cwd: 'myPath' + }); + expect(Utils.spawnProcess.secondCall).to.have.been.calledWithExactly(sinon.match(/^npm/), [ 'run', 's2' ], { + cwd: 'myPath' + }); return null; }); }); @@ -113,58 +94,71 @@ describe('npm', () => { describe('getProdDependencies', () => { it('should use npm ls', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: '{}', stderr: '' })); - return expect(npmModule.getProdDependencies('myPath', 10)).to.be.fulfilled - .then(result => { + return expect(npmModule.getProdDependencies('myPath', 10)).to.be.fulfilled.then(result => { expect(result).to.be.an('object').that.is.empty; expect(Utils.spawnProcess).to.have.been.calledOnce, - expect(Utils.spawnProcess.firstCall).to.have.been.calledWith( - sinon.match(/^npm/), - [ 'ls', '-prod', '-json', '-depth=10' ] - ); + expect(Utils.spawnProcess.firstCall).to.have.been.calledWith(sinon.match(/^npm/), [ + 'ls', + '-prod', + '-json', + '-depth=10' + ]); return null; }); }); it('should default to depth 1', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: '{}', stderr: '' })); - return expect(npmModule.getProdDependencies('myPath')).to.be.fulfilled - .then(result => { + return expect(npmModule.getProdDependencies('myPath')).to.be.fulfilled.then(result => { expect(result).to.be.an('object').that.is.empty; expect(Utils.spawnProcess).to.have.been.calledOnce, - expect(Utils.spawnProcess.firstCall).to.have.been.calledWith( - sinon.match(/^npm/), - [ 'ls', '-prod', '-json', '-depth=1' ] - ); + expect(Utils.spawnProcess.firstCall).to.have.been.calledWith(sinon.match(/^npm/), [ + 'ls', + '-prod', + '-json', + '-depth=1' + ]); return null; }); }); }); it('should reject if npm returns critical and minor errors', () => { - const stderr = 'ENOENT: No such file\nnpm ERR! extraneous: sinon@2.3.8 ./babel-dynamically-entries/node_modules/serverless-webpack/node_modules/sinon\n\n'; + const stderr = + 'ENOENT: No such file\nnpm ERR! extraneous: sinon@2.3.8 ./babel-dynamically-entries/node_modules/serverless-webpack/node_modules/sinon\n\n'; Utils.spawnProcess.returns(BbPromise.reject(new Utils.SpawnError('Command execution failed', '{}', stderr))); - return expect(npmModule.getProdDependencies('myPath', 1)).to.be.rejectedWith('Command execution failed') - .then(() => BbPromise.all([ - // npm ls and npm prune should have been called - expect(Utils.spawnProcess).to.have.been.calledOnce, - expect(Utils.spawnProcess.firstCall).to.have.been.calledWith( - sinon.match(/^npm/), - [ 'ls', '-prod', '-json', '-depth=1' ] - ) - ])); + return expect(npmModule.getProdDependencies('myPath', 1)) + .to.be.rejectedWith('Command execution failed') + .then(() => + BbPromise.all([ + // npm ls and npm prune should have been called + expect(Utils.spawnProcess).to.have.been.calledOnce, + expect(Utils.spawnProcess.firstCall).to.have.been.calledWith(sinon.match(/^npm/), [ + 'ls', + '-prod', + '-json', + '-depth=1' + ]) + ]) + ); }); it('should reject if an error happens without any information in stdout', () => { Utils.spawnProcess.returns(BbPromise.reject(new Utils.SpawnError('Command execution failed', '', ''))); - return expect(npmModule.getProdDependencies('myPath', 1)).to.be.rejectedWith('Command execution failed') - .then(() => BbPromise.all([ - // npm ls and npm prune should have been called - expect(Utils.spawnProcess).to.have.been.calledOnce, - expect(Utils.spawnProcess.firstCall).to.have.been.calledWith( - sinon.match(/^npm/), - [ 'ls', '-prod', '-json', '-depth=1' ] - ) - ])); + return expect(npmModule.getProdDependencies('myPath', 1)) + .to.be.rejectedWith('Command execution failed') + .then(() => + BbPromise.all([ + // npm ls and npm prune should have been called + expect(Utils.spawnProcess).to.have.been.calledOnce, + expect(Utils.spawnProcess.firstCall).to.have.been.calledWith(sinon.match(/^npm/), [ + 'ls', + '-prod', + '-json', + '-depth=1' + ]) + ]) + ); }); it('should ignore minor local NPM errors and log them', () => { @@ -172,7 +166,7 @@ describe('npm', () => { [ 'npm ERR! extraneous: sinon@2.3.8 ./babel-dynamically-entries/node_modules/serverless-webpack/node_modules/sinon', 'npm ERR! missing: internalpackage-1@1.0.0, required by internalpackage-2@1.0.0', - 'npm ERR! peer dep missing: sinon@2.3.8', + 'npm ERR! peer dep missing: sinon@2.3.8' ], '\n' ); @@ -181,7 +175,7 @@ describe('npm', () => { problems: [ 'npm ERR! extraneous: sinon@2.3.8 ./babel-dynamically-entries/node_modules/serverless-webpack/node_modules/sinon', 'npm ERR! missing: internalpackage-1@1.0.0, required by internalpackage-2@1.0.0', - 'npm ERR! peer dep missing: sinon@2.3.8', + 'npm ERR! peer dep missing: sinon@2.3.8' ], dependencies: { '@scoped/vendor': '1.0.0', @@ -190,17 +184,22 @@ describe('npm', () => { } }; - Utils.spawnProcess.returns(BbPromise.reject(new Utils.SpawnError('Command execution failed', JSON.stringify(lsResult), stderr))); - return expect(npmModule.getProdDependencies('myPath', 1)).to.be.fulfilled - .then(dependencies => BbPromise.all([ - // npm ls and npm prune should have been called - expect(Utils.spawnProcess).to.have.been.calledOnce, - expect(Utils.spawnProcess.firstCall).to.have.been.calledWith( - sinon.match(/^npm/), - [ 'ls', '-prod', '-json', '-depth=1' ] - ), - expect(dependencies).to.deep.equal(lsResult), - ])); + Utils.spawnProcess.returns( + BbPromise.reject(new Utils.SpawnError('Command execution failed', JSON.stringify(lsResult), stderr)) + ); + return expect(npmModule.getProdDependencies('myPath', 1)).to.be.fulfilled.then(dependencies => + BbPromise.all([ + // npm ls and npm prune should have been called + expect(Utils.spawnProcess).to.have.been.calledOnce, + expect(Utils.spawnProcess.firstCall).to.have.been.calledWith(sinon.match(/^npm/), [ + 'ls', + '-prod', + '-json', + '-depth=1' + ]), + expect(dependencies).to.deep.equal(lsResult) + ]) + ); }); it('should rebase lock file references', () => { @@ -245,5 +244,4 @@ describe('npm', () => { npmModule.rebaseLockfile('../../locals', fakePackageLockJSON); expect(fakePackageLockJSON).to.deep.equal(expectedPackageLockJSON); }); - }); diff --git a/lib/packagers/yarn.js b/lib/packagers/yarn.js index 2c2b45f4c..4b3721b9b 100644 --- a/lib/packagers/yarn.js +++ b/lib/packagers/yarn.js @@ -1,7 +1,7 @@ 'use strict'; /** * Yarn packager. - * + * * Yarn specific packagerOptions (default): * flat (false) - Use --flat with install * ignoreScripts (false) - Do not execute scripts during install @@ -12,7 +12,8 @@ const BbPromise = require('bluebird'); const Utils = require('../utils'); class Yarn { - static get lockfileName() { // eslint-disable-line lodash/prefer-constant + // eslint-disable-next-line lodash/prefer-constant + static get lockfileName() { return 'yarn.lock'; } @@ -20,18 +21,14 @@ class Yarn { return ['resolutions']; } - static get mustCopyModules() { // eslint-disable-line lodash/prefer-constant + // eslint-disable-next-line lodash/prefer-constant + static get mustCopyModules() { return false; } static getProdDependencies(cwd, depth) { const command = /^win/.test(process.platform) ? 'yarn.cmd' : 'yarn'; - const args = [ - 'list', - `--depth=${depth || 1}`, - '--json', - '--production' - ]; + const args = [ 'list', `--depth=${depth || 1}`, '--json', '--production' ]; // If we need to ignore some errors add them here const ignoredYarnErrors = []; @@ -39,55 +36,67 @@ class Yarn { return Utils.spawnProcess(command, args, { cwd: cwd }) - .catch(err => { - if (err instanceof Utils.SpawnError) { - // Only exit with an error if we have critical npm errors for 2nd level inside - const errors = _.split(err.stderr, '\n'); - const failed = _.reduce(errors, (failed, error) => { - if (failed) { - return true; + .catch(err => { + if (err instanceof Utils.SpawnError) { + // Only exit with an error if we have critical npm errors for 2nd level inside + const errors = _.split(err.stderr, '\n'); + const failed = _.reduce( + errors, + (failed, error) => { + if (failed) { + return true; + } + return ( + !_.isEmpty(error) && + !_.some(ignoredYarnErrors, ignoredError => _.startsWith(error, `npm ERR! ${ignoredError.npmError}`)) + ); + }, + false + ); + + if (!failed && !_.isEmpty(err.stdout)) { + return BbPromise.resolve({ stdout: err.stdout }); } - return !_.isEmpty(error) && !_.some(ignoredYarnErrors, ignoredError => _.startsWith(error, `npm ERR! ${ignoredError.npmError}`)); - }, false); - - if (!failed && !_.isEmpty(err.stdout)) { - return BbPromise.resolve({ stdout: err.stdout }); } - } - return BbPromise.reject(err); - }) - .then(processOutput => processOutput.stdout) - .then(depJson => BbPromise.try(() => JSON.parse(depJson))) - .then(parsedTree => { - const convertTrees = trees => _.reduce(trees, (__, tree) => { - const splitModule = _.split(tree.name, '@'); - // If we have a scoped module we have to re-add the @ - if (_.startsWith(tree.name, '@')) { - splitModule.splice(0, 1); - splitModule[0] = '@' + splitModule[0]; - } - __[_.first(splitModule)] = { - version: _.join(_.tail(splitModule), '@'), - dependencies: convertTrees(tree.children) + return BbPromise.reject(err); + }) + .then(processOutput => processOutput.stdout) + .then(depJson => BbPromise.try(() => JSON.parse(depJson))) + .then(parsedTree => { + const convertTrees = trees => + _.reduce( + trees, + (__, tree) => { + const splitModule = _.split(tree.name, '@'); + // If we have a scoped module we have to re-add the @ + if (_.startsWith(tree.name, '@')) { + splitModule.splice(0, 1); + splitModule[0] = '@' + splitModule[0]; + } + __[_.first(splitModule)] = { + version: _.join(_.tail(splitModule), '@'), + dependencies: convertTrees(tree.children) + }; + return __; + }, + {} + ); + + const trees = _.get(parsedTree, 'data.trees', []); + const result = { + problems: [], + dependencies: convertTrees(trees) }; - return __; - }, {}); - - const trees = _.get(parsedTree, 'data.trees', []); - const result = { - problems: [], - dependencies: convertTrees(trees) - }; - return result; - }); + return result; + }); } static rebaseLockfile(pathToPackageRoot, lockfile) { const fileVersionMatcher = /[^"/]@(?:file:)?((?:\.\/|\.\.\/).*?)[":,]/gm; const replacements = []; let match; - + // Detect all references and create replacement line strings while ((match = fileVersionMatcher.exec(lockfile)) !== null) { replacements.push({ @@ -97,26 +106,19 @@ class Yarn { } // Replace all lines in lockfile - return _.reduce(replacements, (__, replacement) => { - return _.replace(__, replacement.oldRef, replacement.newRef); - }, lockfile); + return _.reduce(replacements, (__, replacement) => _.replace(__, replacement.oldRef, replacement.newRef), lockfile); } static install(cwd, packagerOptions) { const command = /^win/.test(process.platform) ? 'yarn.cmd' : 'yarn'; - const args = [ - 'install', - '--frozen-lockfile', - '--non-interactive' - ]; + const args = [ 'install', '--frozen-lockfile', '--non-interactive' ]; // Convert supported packagerOptions if (packagerOptions.ignoreScripts) { args.push('--ignore-scripts'); } - return Utils.spawnProcess(command, args, { cwd }) - .return(); + return Utils.spawnProcess(command, args, { cwd }).return(); } // "Yarn install" prunes automatically @@ -127,14 +129,10 @@ class Yarn { static runScripts(cwd, scriptNames) { const command = /^win/.test(process.platform) ? 'yarn.cmd' : 'yarn'; return BbPromise.mapSeries(scriptNames, scriptName => { - const args = [ - 'run', - scriptName - ]; + const args = [ 'run', scriptName ]; return Utils.spawnProcess(command, args, { cwd }); - }) - .return(); + }).return(); } } diff --git a/lib/packagers/yarn.test.js b/lib/packagers/yarn.test.js index d77ac154d..0e58d46f0 100644 --- a/lib/packagers/yarn.test.js +++ b/lib/packagers/yarn.test.js @@ -48,8 +48,7 @@ describe('yarn', () => { describe('getProdDependencies', () => { it('should use yarn list', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: '{}', stderr: '' })); - return expect(yarnModule.getProdDependencies('myPath', 1)).to.be.fulfilled - .then(result => { + return expect(yarnModule.getProdDependencies('myPath', 1)).to.be.fulfilled.then(result => { expect(result).to.be.an('object'); expect(Utils.spawnProcess).to.have.been.calledOnce, expect(Utils.spawnProcess.firstCall).to.have.been.calledWith( @@ -97,22 +96,22 @@ describe('yarn', () => { '@sls/webpack': { version: '1.0.0', dependencies: {} - }, + } } }; Utils.spawnProcess.returns(BbPromise.resolve({ stdout: testYarnResult, stderr: '' })); - return expect(yarnModule.getProdDependencies('myPath', 1)).to.be.fulfilled - .then(result => { + return expect(yarnModule.getProdDependencies('myPath', 1)).to.be.fulfilled.then(result => { expect(result).to.deep.equal(expectedResult); return null; }); }); it('should reject on critical yarn errors', () => { - Utils.spawnProcess.returns(BbPromise.reject(new Utils.SpawnError('Exited with code 1', '', 'Yarn failed.\nerror Could not find module.'))); + Utils.spawnProcess.returns( + BbPromise.reject(new Utils.SpawnError('Exited with code 1', '', 'Yarn failed.\nerror Could not find module.')) + ); return expect(yarnModule.getProdDependencies('myPath', 1)).to.be.rejectedWith('Exited with code 1'); }); - }); describe('rebaseLockfile', () => { @@ -198,7 +197,7 @@ describe('yarn', () => { version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" `; - + expect(yarnModule.rebaseLockfile('../../project', testContent)).to.equal(expectedContent); }); }); @@ -206,8 +205,7 @@ describe('yarn', () => { describe('install', () => { it('should use yarn install', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: 'installed successfully', stderr: '' })); - return expect(yarnModule.install('myPath', {})).to.be.fulfilled - .then(result => { + return expect(yarnModule.install('myPath', {})).to.be.fulfilled.then(result => { expect(result).to.be.undefined; expect(Utils.spawnProcess).to.have.been.calledOnce; expect(Utils.spawnProcess).to.have.been.calledWithExactly( @@ -223,8 +221,7 @@ describe('yarn', () => { it('should use ignoreScripts option', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: 'installed successfully', stderr: '' })); - return expect(yarnModule.install('myPath', { ignoreScripts: true })).to.be.fulfilled - .then(result => { + return expect(yarnModule.install('myPath', { ignoreScripts: true })).to.be.fulfilled.then(result => { expect(result).to.be.undefined; expect(Utils.spawnProcess).to.have.been.calledOnce; expect(Utils.spawnProcess).to.have.been.calledWithExactly( @@ -251,8 +248,7 @@ describe('yarn', () => { }); it('should call install', () => { - return expect(yarnModule.prune('myPath', {})).to.be.fulfilled - .then(() => { + return expect(yarnModule.prune('myPath', {})).to.be.fulfilled.then(() => { expect(installStub).to.have.been.calledOnce; expect(installStub).to.have.been.calledWithExactly('myPath', {}); return null; @@ -263,27 +259,17 @@ describe('yarn', () => { describe('runScripts', () => { it('should use yarn run for the given scripts', () => { Utils.spawnProcess.returns(BbPromise.resolve({ stdout: 'success', stderr: '' })); - return expect(yarnModule.runScripts('myPath', [ 's1', 's2' ])).to.be.fulfilled - .then(result => { + return expect(yarnModule.runScripts('myPath', [ 's1', 's2' ])).to.be.fulfilled.then(result => { expect(result).to.be.undefined; expect(Utils.spawnProcess).to.have.been.calledTwice; - expect(Utils.spawnProcess.firstCall).to.have.been.calledWithExactly( - sinon.match(/^yarn/), - [ 'run', 's1' ], - { - cwd: 'myPath' - } - ); - expect(Utils.spawnProcess.secondCall).to.have.been.calledWithExactly( - sinon.match(/^yarn/), - [ 'run', 's2' ], - { - cwd: 'myPath' - } - ); + expect(Utils.spawnProcess.firstCall).to.have.been.calledWithExactly(sinon.match(/^yarn/), [ 'run', 's1' ], { + cwd: 'myPath' + }); + expect(Utils.spawnProcess.secondCall).to.have.been.calledWithExactly(sinon.match(/^yarn/), [ 'run', 's2' ], { + cwd: 'myPath' + }); return null; }); }); }); - -}); \ No newline at end of file +}); diff --git a/lib/prepareLocalInvoke.test.js b/lib/prepareLocalInvoke.test.js index 4b6284771..180098d9e 100644 --- a/lib/prepareLocalInvoke.test.js +++ b/lib/prepareLocalInvoke.test.js @@ -40,10 +40,13 @@ describe('prepareLocalInvoke', () => { sandbox.stub(process, 'chdir'); sandbox.stub(serverless.service, 'getFunction'); - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); }); afterEach(() => { @@ -56,7 +59,7 @@ describe('prepareLocalInvoke', () => { module.webpackOutputPath = '.'; module.serverless.config.servicePath = './servicePath'; module.prepareLocalInvoke(); - + expect(module.originalServicePath).to.equal('./servicePath'); }); @@ -69,7 +72,7 @@ describe('prepareLocalInvoke', () => { module.webpackOutputPath = '.webpack'; module.serverless.config.servicePath = './servicePath'; module.prepareLocalInvoke(); - + expect(process.chdir).to.have.been.calledWithExactly(path.join('.webpack', 'myFunc')); }); @@ -80,7 +83,7 @@ describe('prepareLocalInvoke', () => { module.webpackOutputPath = '.webpack'; module.serverless.config.servicePath = './servicePath'; module.prepareLocalInvoke(); - + expect(process.chdir).to.have.been.calledWithExactly(path.join('.webpack', 'service')); }); @@ -91,7 +94,7 @@ describe('prepareLocalInvoke', () => { module.serverless.config.servicePath = './servicePath'; _.unset(module, 'serverless.config.serverless.processedInput.options.path'); module.prepareLocalInvoke(); - + expect(module.originalServicePath).to.equal('./servicePath'); }); }); diff --git a/lib/prepareOfflineInvoke.js b/lib/prepareOfflineInvoke.js index e7d468364..f00cc6fc3 100644 --- a/lib/prepareOfflineInvoke.js +++ b/lib/prepareOfflineInvoke.js @@ -9,15 +9,15 @@ const path = require('path'); module.exports = { prepareOfflineInvoke() { - // Use service packaging for compile _.set(this.serverless, 'service.package.individually', false); - return this.serverless.pluginManager.spawn('webpack:validate') - .then(() => { + return this.serverless.pluginManager.spawn('webpack:validate').then(() => { // Set offline location automatically if not set manually if (!this.options.location && !_.get(this.serverless, 'service.custom.serverless-offline.location')) { - _.set(this.serverless, 'service.custom.serverless-offline.location', + _.set( + this.serverless, + 'service.custom.serverless-offline.location', path.relative(this.serverless.config.servicePath, path.join(this.webpackOutputPath, 'service')) ); } diff --git a/lib/prepareOfflineInvoke.test.js b/lib/prepareOfflineInvoke.test.js index 6c7418c10..4bfcdcf6f 100644 --- a/lib/prepareOfflineInvoke.test.js +++ b/lib/prepareOfflineInvoke.test.js @@ -31,10 +31,13 @@ describe('prepareOfflineInvoke', () => { log: sandbox.stub() }; sandbox.stub(serverless.pluginManager, 'spawn'); - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); }); afterEach(() => { @@ -47,8 +50,7 @@ describe('prepareOfflineInvoke', () => { module.webpackOutputPath = '.'; module.serverless.service.package = {}; - return expect(module.prepareOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareOfflineInvoke()).to.be.fulfilled.then(() => { expect(module.serverless.service.package).to.have.a.property('individually').that.is.false; return null; }); @@ -62,8 +64,7 @@ describe('prepareOfflineInvoke', () => { individually: true }; - return expect(module.prepareOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareOfflineInvoke()).to.be.fulfilled.then(() => { expect(module.serverless.service.package).to.have.a.property('individually').that.is.false; return null; }); @@ -74,8 +75,7 @@ describe('prepareOfflineInvoke', () => { serverless.config.servicePath = 'myPath'; module.webpackOutputPath = '.'; - return expect(module.prepareOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareOfflineInvoke()).to.be.fulfilled.then(() => { expect(serverless.pluginManager.spawn).to.have.been.calledOnce; expect(serverless.pluginManager.spawn).to.have.been.calledWithExactly('webpack:validate'); return null; @@ -95,8 +95,7 @@ describe('prepareOfflineInvoke', () => { serverless.config.servicePath = '.'; module.webpackOutputPath = '.'; - return expect(module.prepareOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareOfflineInvoke()).to.be.fulfilled.then(() => { expect(serverless.service).to.have.a.nested.property('custom.serverless-offline.location', 'service'); return null; }); @@ -108,8 +107,7 @@ describe('prepareOfflineInvoke', () => { module.webpackOutputPath = '.'; _.set(module.serverless, 'service.custom.serverless-offline.location', 'myLocation'); - return expect(module.prepareOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareOfflineInvoke()).to.be.fulfilled.then(() => { expect(serverless.service).to.have.a.nested.property('custom.serverless-offline.location', 'myLocation'); return null; }); @@ -123,8 +121,7 @@ describe('prepareOfflineInvoke', () => { location: 'myLocation' }; - return expect(module.prepareOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareOfflineInvoke()).to.be.fulfilled.then(() => { expect(serverless.service).to.not.have.a.nested.property('custom.serverless-offline.location'); return null; }); diff --git a/lib/prepareStepOfflineInvoke.js b/lib/prepareStepOfflineInvoke.js index ddc12fec1..16e421a9c 100644 --- a/lib/prepareStepOfflineInvoke.js +++ b/lib/prepareStepOfflineInvoke.js @@ -11,14 +11,15 @@ module.exports = { prepareStepOfflineInvoke() { _.set(this.serverless, 'service.package.individually', false); - return this.serverless.pluginManager.spawn('webpack:validate') - .then(() => { - if (!this.options.location && !_.get(this.serverless, 'service.custom.stepFunctionsOffline.location')) { - _.set(this.serverless, 'service.custom.stepFunctionsOffline.location', - path.relative(this.serverless.config.servicePath, path.join(this.webpackOutputPath, 'service')) - ); - } - return null; - }); + return this.serverless.pluginManager.spawn('webpack:validate').then(() => { + if (!this.options.location && !_.get(this.serverless, 'service.custom.stepFunctionsOffline.location')) { + _.set( + this.serverless, + 'service.custom.stepFunctionsOffline.location', + path.relative(this.serverless.config.servicePath, path.join(this.webpackOutputPath, 'service')) + ); + } + return null; + }); } }; diff --git a/lib/run.js b/lib/run.js index 4e90583cc..fb964aa50 100644 --- a/lib/run.js +++ b/lib/run.js @@ -25,8 +25,8 @@ module.exports = { if (err) { throw err; } - - BbPromise.try(() => { // eslint-disable-line promise/catch-or-return, promise/no-promise-in-callback + // eslint-disable-next-line promise/catch-or-return, promise/no-promise-in-callback + BbPromise.try(() => { if (this.originalServicePath) { process.chdir(this.originalServicePath); this.serverless.config.servicePath = this.originalServicePath; @@ -43,8 +43,7 @@ module.exports = { } this.options.verbose && this.serverless.cli.log(`Invoke ${command}`); return this.serverless.pluginManager.spawn(command); - }) - .then(() => this.serverless.cli.log('Waiting for changes ...')); + }).then(() => this.serverless.cli.log('Waiting for changes ...')); }); - }, + } }; diff --git a/lib/runPluginSupport.js b/lib/runPluginSupport.js index 8f1584cbe..2fcc45a75 100644 --- a/lib/runPluginSupport.js +++ b/lib/runPluginSupport.js @@ -25,24 +25,20 @@ module.exports = { // does not offer any detailed hooks that could be overridden to do // a deploy only. Running the whole run command will lead to an error // because the functions are already registered in the event gateway - const deployFunctionsToLocalEmulator = require( - path.join( - this.serverless.config.serverlessPath, - 'plugins', - 'run', - 'utils', - 'deployFunctionsToLocalEmulator' - ) - ); - const getLocalRootUrl = require( - path.join( - this.serverless.config.serverlessPath, - 'plugins', - 'run', - 'utils', - 'getLocalRootUrl' - ) - ); + const deployFunctionsToLocalEmulator = require(path.join( + this.serverless.config.serverlessPath, + 'plugins', + 'run', + 'utils', + 'deployFunctionsToLocalEmulator' + )); + const getLocalRootUrl = require(path.join( + this.serverless.config.serverlessPath, + 'plugins', + 'run', + 'utils', + 'getLocalRootUrl' + )); // Reset configuration this.serverless.config.servicePath = this.originalServicePath; @@ -50,11 +46,12 @@ module.exports = { this.webpackConfig.output.path = this.webpackOutputPath; process.chdir(this.serverless.config.servicePath); - return this.hooks['before:run:run']() - .then(() => deployFunctionsToLocalEmulator( - this.serverless.service, - this.serverless.config.servicePath, - getLocalRootUrl(this.options.lport) - )); + return this.hooks['before:run:run']().then(() => + deployFunctionsToLocalEmulator( + this.serverless.service, + this.serverless.config.servicePath, + getLocalRootUrl(this.options.lport) + ) + ); } }; diff --git a/lib/utils.js b/lib/utils.js index 1db482d3b..7609265c8 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -15,15 +15,14 @@ function guid() { /** * Remove the specified module from the require cache. - * @param {string} moduleName + * @param {string} moduleName */ function purgeCache(moduleName) { - return searchAndProcessCache(moduleName, function (mod) { + return searchAndProcessCache(moduleName, function(mod) { delete require.cache[mod.id]; - }) - .then(() => { + }).then(() => { _.forEach(_.keys(module.constructor._pathCache), function(cacheKey) { - if (cacheKey.indexOf(moduleName)>0) { + if (cacheKey.indexOf(moduleName) > 0) { delete module.constructor._pathCache[cacheKey]; } }); @@ -34,7 +33,7 @@ function purgeCache(moduleName) { function searchAndProcessCache(moduleName, processor) { let mod_src = require.resolve(moduleName); const visitedModules = []; - if (mod_src && ((mod_src = require.cache[mod_src]) !== undefined)) { + if (mod_src && (mod_src = require.cache[mod_src]) !== undefined) { const modStack = [mod_src]; while (!_.isEmpty(modStack)) { @@ -102,5 +101,5 @@ module.exports = { purgeCache, searchAndProcessCache, SpawnError, - spawnProcess, + spawnProcess }; diff --git a/lib/utils.test.js b/lib/utils.test.js index 658934df3..a0a6479db 100644 --- a/lib/utils.test.js +++ b/lib/utils.test.js @@ -28,7 +28,7 @@ describe('Utils', () => { describe('guid', () => { it('should return different unique ids', () => { const guids = []; - for (let i=0; i<10; i++) { + for (let i = 0; i < 10; i++) { guids.push(Utils.guid()); } @@ -40,9 +40,15 @@ describe('Utils', () => { describe('SpawnError', () => { it('should store stdout and stderr', () => { const err = new Utils.SpawnError('message', 'stdout', 'stderr'); - expect(err).to.have.a.property('message').that.equals('message'); - expect(err).to.have.a.property('stdout').that.equals('stdout'); - expect(err).to.have.a.property('stderr').that.equals('stderr'); + expect(err) + .to.have.a.property('message') + .that.equals('message'); + expect(err) + .to.have.a.property('stdout') + .that.equals('stdout'); + expect(err) + .to.have.a.property('stderr') + .that.equals('stderr'); }); it('should print message and stderr', () => { @@ -76,8 +82,7 @@ describe('Utils', () => { it('should call child_process.spawn', () => { childMock.on.reset(); childMock.on.withArgs('close').yields(0); - return expect(Utils.spawnProcess('cmd', [])).to.be.fulfilled - .then(result => { + return expect(Utils.spawnProcess('cmd', [])).to.be.fulfilled.then(result => { expect(childProcess.spawn).to.have.been.calledOnce; expect(result).to.have.a.property('stdout').that.is.empty; expect(result).to.have.a.property('stderr').that.is.empty; @@ -90,10 +95,13 @@ describe('Utils', () => { childMock.stderr.on.withArgs('data').yields('myErrData'); childMock.on.reset(); childMock.on.withArgs('close').yields(0); - return expect(Utils.spawnProcess('cmd', [])).to.be.fulfilled - .then(result => { - expect(result).to.have.a.property('stdout').that.equals('myOutData'); - expect(result).to.have.a.property('stderr').that.equals('myErrData'); + return expect(Utils.spawnProcess('cmd', [])).to.be.fulfilled.then(result => { + expect(result) + .to.have.a.property('stdout') + .that.equals('myOutData'); + expect(result) + .to.have.a.property('stderr') + .that.equals('myErrData'); return null; }); }); diff --git a/lib/validate.js b/lib/validate.js index a6ebc580f..ceaef00a9 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -13,12 +13,7 @@ const Configuration = require('./Configuration'); * This should cover most of the cases. For complex setups the user should * build his own entries with help of the other exports. */ -const preferredExtensions = [ - '.js', - '.ts', - '.jsx', - '.tsx' -]; +const preferredExtensions = [ '.js', '.ts', '.jsx', '.tsx' ]; module.exports = { validate() { @@ -39,22 +34,25 @@ module.exports = { if (_.isEmpty(files)) { // If we cannot find any handler we should terminate with an error - throw new this.serverless.classes.Error(`No matching handler found for '${fileName}' in '${this.serverless.config.servicePath}'. Check your service definition.`); + throw new this.serverless.classes.Error( + `No matching handler found for '${fileName}' in '${ + this.serverless.config.servicePath + }'. Check your service definition.` + ); } // Move preferred file extensions to the beginning const sortedFiles = _.uniq( _.concat( - _.sortBy( - _.filter(files, file => _.includes(preferredExtensions, path.extname(file))), - a => _.size(a) - ), + _.sortBy(_.filter(files, file => _.includes(preferredExtensions, path.extname(file))), a => _.size(a)), files ) ); if (_.size(sortedFiles) > 1) { - this.serverless.cli.log(`WARNING: More than one matching handlers found for '${fileName}'. Using '${_.first(sortedFiles)}'.`); + this.serverless.cli.log( + `WARNING: More than one matching handlers found for '${fileName}'. Using '${_.first(sortedFiles)}'.` + ); } return path.extname(_.first(sortedFiles)); }; @@ -65,7 +63,9 @@ module.exports = { const handlerFile = getHandlerFile(handler); if (!handlerFile) { _.get(this.serverless, 'service.provider.name') !== 'google' && - this.serverless.cli.log(`\nWARNING: Entry for ${name}@${handler} could not be retrieved.\nPlease check your service config if you want to use lib.entries.`); + this.serverless.cli.log( + `\nWARNING: Entry for ${name}@${handler} could not be retrieved.\nPlease check your service config if you want to use lib.entries.` + ); return {}; } const ext = getEntryExtension(handlerFile); @@ -78,9 +78,12 @@ module.exports = { // Initialize plugin configuration this.configuration = new Configuration(this.serverless.service.custom); - this.options.verbose && this.serverless.cli.log(`Using configuration:\n${JSON.stringify(this.configuration, null, 2)}`); + this.options.verbose && + this.serverless.cli.log(`Using configuration:\n${JSON.stringify(this.configuration, null, 2)}`); if (this.configuration.hasLegacyConfig) { - this.serverless.cli.log('Legacy configuration detected. Consider to use "custom.webpack" as object (see README).'); + this.serverless.cli.log( + 'Legacy configuration detected. Consider to use "custom.webpack" as object (see README).' + ); } this.webpackConfig = this.configuration.config || this.configuration.webpackConfig; @@ -108,8 +111,11 @@ module.exports = { if (_.isString(this.webpackConfig)) { const webpackConfigFilePath = path.join(this.serverless.config.servicePath, this.webpackConfig); if (!this.serverless.utils.fileExistsSync(webpackConfigFilePath)) { - return BbPromise.reject(new this.serverless.classes - .Error('The webpack plugin could not find the configuration file at: ' + webpackConfigFilePath)); + return BbPromise.reject( + new this.serverless.classes.Error( + 'The webpack plugin could not find the configuration file at: ' + webpackConfigFilePath + ) + ); } try { this.webpackConfig = require(webpackConfigFilePath); @@ -138,7 +144,7 @@ module.exports = { this.webpackConfig.output = { libraryTarget: 'commonjs', path: outputPath, - filename: '[name].js', + filename: '[name].js' }; } @@ -150,8 +156,7 @@ module.exports = { if (this.skipCompile) { this.serverless.cli.log('Skipping build and using existing compiled output'); if (!fse.pathExistsSync(this.webpackConfig.output.path)) { - return BbPromise.reject(new this.serverless.classes - .Error('No compiled output found')); + return BbPromise.reject(new this.serverless.classes.Error('No compiled output found')); } this.keepOutputDirectory = true; } @@ -168,25 +173,25 @@ module.exports = { this.multiCompile = true; if (this.webpackConfig.entry && !_.isEqual(this.webpackConfig.entry, entries)) { - return BbPromise.reject(new this.serverless.classes - .Error('Webpack entry must be automatically resolved when package.individually is set to true. ' + - 'In webpack.config.js, remove the entry declaration or set entry to slsw.lib.entries.')); + return BbPromise.reject( + new this.serverless.classes.Error( + 'Webpack entry must be automatically resolved when package.individually is set to true. ' + + 'In webpack.config.js, remove the entry declaration or set entry to slsw.lib.entries.' + ) + ); } // Lookup associated Serverless functions - const allEntryFunctions = _.map( - this.serverless.service.getAllFunctions(), - funcName => { - const func = this.serverless.service.getFunction(funcName); - const handler = func.handler; - const handlerFile = path.relative('.', getHandlerFile(handler)); - return { - handlerFile, - funcName, - func - }; - } - ); + const allEntryFunctions = _.map(this.serverless.service.getAllFunctions(), funcName => { + const func = this.serverless.service.getFunction(funcName); + const handler = func.handler; + const handlerFile = path.relative('.', getHandlerFile(handler)); + return { + handlerFile, + funcName, + func + }; + }); this.entryFunctions = _.flatMap(entries, (value, key) => { const entry = path.relative('.', value); @@ -228,5 +233,5 @@ module.exports = { } else { return processConfig(this.webpackConfig); } - }, + } }; diff --git a/lib/wpwatch.js b/lib/wpwatch.js index 2bcd0991c..aa00a3583 100644 --- a/lib/wpwatch.js +++ b/lib/wpwatch.js @@ -25,14 +25,14 @@ module.exports = { let currentCompileWatch = null; // This allows us to hold the compile until "webpack:compile:watch" has resolved - const beforeCompile = () => ( - new BbPromise((resolve) => { + const beforeCompile = () => + new BbPromise(resolve => { // eslint-disable-next-line promise/catch-or-return BbPromise.resolve(currentCompileWatch) // Forwarding the error to the then so we don't display it twice // (once when it was originally thrown, and once when the promise rejects) .catch(error => error) - .then((error) => { + .then(error => { if (error) { return null; } @@ -41,8 +41,7 @@ module.exports = { resolve(); return null; }); - }) - ); + }); const compiler = webpack(this.webpackConfig); @@ -55,8 +54,9 @@ module.exports = { compiler.hooks.beforeCompile.tapPromise('webpack:compile:watch', beforeCompile); } else if (hasPlugins) { compiler.plugin('before-compile', (compilationParams, callback) => { - // eslint-disable-next-line promise/no-callback-in-promise - beforeCompile().then(callback).catch(_.noop); + beforeCompile() + .then(callback) // eslint-disable-line promise/no-callback-in-promise + .catch(_.noop); }); } @@ -71,7 +71,7 @@ module.exports = { // This starts the watch and waits for the immediate compile that follows to end or fail. let lastHash = null; - const startWatch = (callback) => { + const startWatch = callback => { let firstRun = true; compiler.watch(watchOptions, (err, stats) => { if (err) { @@ -82,7 +82,8 @@ module.exports = { throw err; } - process.env.SLS_DEBUG && this.serverless.cli.log(`Webpack watch invoke: HASH NEW=${stats.hash} CUR=${lastHash}`); + process.env.SLS_DEBUG && + this.serverless.cli.log(`Webpack watch invoke: HASH NEW=${stats.hash} CUR=${lastHash}`); // If the file hash did not change there were no effective code changes detected // (comment changes do not change the compile hash and do not account for a rebuild!) @@ -108,9 +109,10 @@ module.exports = { this.serverless.cli.log('Watching for changes...'); callback(); } else if (canEmit && currentCompileWatch === null) { - currentCompileWatch = BbPromise.resolve( // eslint-disable-line promise/no-promise-in-callback - this.serverless.pluginManager.spawn('webpack:compile:watch') - ).then(() => this.serverless.cli.log('Watching for changes...')); + // eslint-disable-next-line promise/no-promise-in-callback + currentCompileWatch = BbPromise.resolve(this.serverless.pluginManager.spawn('webpack:compile:watch')).then( + () => this.serverless.cli.log('Watching for changes...') + ); } }); }; @@ -118,5 +120,5 @@ module.exports = { return BbPromise.fromCallback(cb => { startWatch(cb); }); - }, + } }; diff --git a/package-lock.json b/package-lock.json index 3ec10a8d2..b2279d295 100644 --- a/package-lock.json +++ b/package-lock.json @@ -184,6 +184,12 @@ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "acorn": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", @@ -234,6 +240,12 @@ } } }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, "ansi": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", @@ -528,6 +540,44 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "babel-eslint": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.5.tgz", @@ -542,6 +592,24 @@ "eslint-visitor-keys": "^1.0.0" } }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + } + } + }, "babylon": { "version": "7.0.0-beta.44", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", @@ -636,6 +704,12 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==" }, + "boolify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/boolify/-/boolify-1.0.1.tgz", + "integrity": "sha1-tcCeF8rNET0Rt7s+04TMASmU2Gs=", + "dev": true + }, "boxen": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", @@ -831,6 +905,23 @@ } } }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "^0.2.0" + }, + "dependencies": { + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + } + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -843,6 +934,17 @@ "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true }, + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, "capture-stack-trace": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", @@ -918,6 +1020,12 @@ "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", "dev": true }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -1071,6 +1179,12 @@ } } }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -1118,6 +1232,12 @@ "graceful-readlink": ">= 1.0.0" } }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -1215,6 +1335,12 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -1573,6 +1699,12 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.0.tgz", "integrity": "sha1-BWaVFQ16qTI3yn43isOxaCt5Y7k=" }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2080,23 +2212,6 @@ } } }, - "eslint-config-prettier": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-4.2.0.tgz", - "integrity": "sha512-y0uWc/FRfrHhpPZCYflWC8aE0KRJRY04rdZVfl8cL3sEZmOYyaBdhdlQPjKZBnuRMyLVK+JUZr7HaZFClQiH4w==", - "dev": true, - "requires": { - "get-stdin": "^6.0.0" - }, - "dependencies": { - "get-stdin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", - "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", - "dev": true - } - } - }, "eslint-import-resolver-node": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", @@ -2634,6 +2749,38 @@ "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", "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, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + }, + "dependencies": { + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + } + } + }, "flatted": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", @@ -3679,6 +3826,12 @@ "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", "dev": true }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", @@ -4657,6 +4810,18 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "dev": true + }, "lodash.pad": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", @@ -4675,6 +4840,12 @@ "integrity": "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=", "dev": true }, + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, "lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", @@ -4743,6 +4914,49 @@ } } }, + "loglevel": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.3.tgz", + "integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==", + "dev": true + }, + "loglevel-colored-level-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", + "integrity": "sha1-akAhj9x64V/HbD0PPmdsRlOIYD4=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, "lolex": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.0.1.tgz", @@ -4802,6 +5016,15 @@ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz", "integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y=" }, + "make-plural": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz", + "integrity": "sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -4817,6 +5040,12 @@ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -4871,6 +5100,41 @@ } } }, + "messageformat": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/messageformat/-/messageformat-1.1.1.tgz", + "integrity": "sha512-Q0uXcDtF5pEZsVSyhzDOGgZZK6ykN79VY9CwU3Nv0gsqx62BjdJW0MT+63UkHQ4exe3HE33ZlxR2/YwoJarRTg==", + "dev": true, + "requires": { + "glob": "~7.0.6", + "make-plural": "^4.1.1", + "messageformat-parser": "^1.1.0", + "nopt": "~3.0.6", + "reserved-words": "^0.1.2" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "messageformat-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-1.1.0.tgz", + "integrity": "sha512-Hwem6G3MsKDLS1FtBRGIs8T50P1Q00r3srS6QJePCFbad9fq0nYxwf3rnU2BreApRGhmpKMV7oZI06Sy1c9TPA==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -5141,6 +5405,15 @@ "is-stream": "^1.0.1" } }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -5814,6 +6087,12 @@ "semver-compare": "^1.0.0" } }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -5838,75 +6117,988 @@ "integrity": "sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==", "dev": true }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "promise-queue": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", - "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=", - "dev": true - }, - "property-expr": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", - "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", - "dev": true - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, - "psl": { - "version": "1.1.31", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", - "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true - }, + "prettier-eslint": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-8.8.2.tgz", + "integrity": "sha512-2UzApPuxi2yRoyMlXMazgR6UcH9DKJhNgCviIwY3ixZ9THWSSrUww5vkiZ3C48WvpFl1M1y/oU63deSy1puWEA==", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^4.0.0", + "indent-string": "^3.2.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^1.7.0", + "pretty-format": "^23.0.1", + "require-relative": "^0.8.7", + "typescript": "^2.5.1", + "typescript-eslint-parser": "^16.0.0", + "vue-eslint-parser": "^2.0.2" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "cli-cursor": { + "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, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "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 + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + } + } + }, + "prettier-eslint-cli": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/prettier-eslint-cli/-/prettier-eslint-cli-4.7.1.tgz", + "integrity": "sha512-hQbsGaEVz97oBBcKdsJ46khv0kOGkMyWrXzcFOXW6X8UuetZ/j0yDJkNJgUTVc6PVFbbzBXk+qgd5vos9qzXPQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "babel-runtime": "^6.23.0", + "boolify": "^1.0.0", + "camelcase-keys": "^4.1.0", + "chalk": "2.3.0", + "common-tags": "^1.4.0", + "eslint": "^4.5.0", + "find-up": "^2.1.0", + "get-stdin": "^5.0.1", + "glob": "^7.1.1", + "ignore": "^3.2.7", + "indent-string": "^3.1.0", + "lodash.memoize": "^4.1.2", + "loglevel-colored-level-prefix": "^1.0.0", + "messageformat": "^1.0.2", + "prettier-eslint": "^8.5.0", + "rxjs": "^5.3.0", + "yargs": "10.0.3" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "cli-cursor": { + "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, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "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, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "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 + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + } + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "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, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz", + "integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==", + "dev": true, + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^8.0.0" + } + }, + "yargs-parser": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", + "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-queue": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", + "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=", + "dev": true + }, + "property-expr": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", + "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", + "dev": true + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, "raven": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/raven/-/raven-1.2.1.tgz", @@ -6166,6 +7358,36 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + } + } + }, + "reserved-words": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz", + "integrity": "sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=", + "dev": true + }, "resolve": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz", @@ -6249,6 +7471,21 @@ "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", "dev": true }, + "rx-lite": { + "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, + "requires": { + "rx-lite": "*" + } + }, "rxjs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.1.tgz", @@ -7475,6 +8712,22 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "dev": true + }, + "typescript-eslint-parser": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-16.0.1.tgz", + "integrity": "sha512-IKawLTu4A2xN3aN/cPLxvZ0bhxZHILGDKTZWvWNJ3sLNhJ3PjfMEDQmR2VMpdRPrmWOadgWXRwjLBzSA8AGsaQ==", + "dev": true, + "requires": { + "lodash.unescape": "4.0.1", + "semver": "5.5.0" + } + }, "uglify-js": { "version": "3.5.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.9.tgz", @@ -7753,6 +9006,70 @@ "extsprintf": "^1.2.0" } }, + "vue-eslint-parser": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz", + "integrity": "sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.2", + "esquery": "^1.0.0", + "lodash": "^4.17.4" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "walkdir": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz", diff --git a/package.json b/package.json index 8fe0cf891..660a4bc97 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "homepage": "https://github.com/serverless-heaven/serverless-webpack#readme", "scripts": { "test": "nyc ./node_modules/mocha/bin/_mocha tests/all index.test.js \"lib/**/*.test.js\" -R spec --recursive", - "eslint": "node node_modules/eslint/bin/eslint.js --ext .js lib" + "eslint": "eslint --ext .js *.js lib tests", + "format": "prettier-eslint \"*.js\" \"lib/**/*.js\" \"tests/**/*.js\" --write" }, "nyc": { "all": true, @@ -61,7 +62,6 @@ "chai-as-promised": "^7.1.1", "coveralls": "^3.0.3", "eslint": "^5.16.0", - "eslint-config-prettier": "^4.2.0", "eslint-plugin-import": "^2.17.2", "eslint-plugin-lodash": "^5.1.0", "eslint-plugin-promise": "^4.1.1", @@ -71,6 +71,7 @@ "mockery": "^2.1.0", "nyc": "^14.1.0", "prettier": "^1.17.0", + "prettier-eslint-cli": "^4.7.1", "serverless": "^1.41.1", "sinon": "^7.3.2", "sinon-chai": "^3.3.0" diff --git a/prettier.config.js b/prettier.config.js index 6f216fff7..ea7ed46d0 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -1,7 +1,8 @@ module.exports = { - arrowParens: 'always', - bracketSpacing: false, + printWidth: 120, + arrowParens: 'avoid', + bracketSpacing: true, semi: true, singleQuote: true, - trailingComma: 'all', + trailingComma: 'none' }; diff --git a/tests/cleanup.test.js b/tests/cleanup.test.js index e7d9a6dd6..4d9eda2d2 100644 --- a/tests/cleanup.test.js +++ b/tests/cleanup.test.js @@ -51,12 +51,15 @@ describe('cleanup', () => { }; dirExistsSyncStub = sandbox.stub(serverless.utils, 'dirExistsSync'); - module = _.assign({ - serverless, - options: {}, - webpackOutputPath: 'my/Output/Path', - configuration: {} - }, baseModule); + module = _.assign( + { + serverless, + options: {}, + webpackOutputPath: 'my/Output/Path', + configuration: {} + }, + baseModule + ); }); afterEach(() => { @@ -68,8 +71,7 @@ describe('cleanup', () => { dirExistsSyncStub.returns(true); fseMock.removeSync.reset(); - return expect(module.cleanup()).to.be.fulfilled - .then(() => { + return expect(module.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.have.been.calledOnce; expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path'); expect(fseMock.removeSync).to.have.been.calledOnce; @@ -81,8 +83,7 @@ describe('cleanup', () => { dirExistsSyncStub.returns(false); fseMock.removeSync.reset(); - return expect(module.cleanup()).to.be.fulfilled - .then(() => { + return expect(module.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.have.been.calledOnce; expect(dirExistsSyncStub).to.have.been.calledWith('my/Output/Path'); expect(fseMock.removeSync).to.not.have.been.called; @@ -97,11 +98,10 @@ describe('cleanup', () => { const configuredModule = _.assign({}, module, { configuration: { keepOutputDirectory: true } }); - return expect(configuredModule.cleanup()).to.be.fulfilled - .then(() => { + return expect(configuredModule.cleanup()).to.be.fulfilled.then(() => { expect(dirExistsSyncStub).to.not.have.been.calledOnce; expect(fseMock.removeSync).to.not.have.been.called; return null; }); - }) + }); }); diff --git a/tests/compile.test.js b/tests/compile.test.js index ec8a88ce9..c0bcb672a 100644 --- a/tests/compile.test.js +++ b/tests/compile.test.js @@ -44,10 +44,13 @@ describe('compile', () => { consoleLog: sandbox.stub() }; - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); }); afterEach(() => { @@ -62,8 +65,7 @@ describe('compile', () => { it('should compile with webpack from a context configuration', () => { const testWebpackConfig = 'testconfig'; module.webpackConfig = testWebpackConfig; - return expect(module.compile()).to.be.fulfilled - .then(() => { + return expect(module.compile()).to.be.fulfilled.then(() => { expect(webpackMock).to.have.been.calledWith(testWebpackConfig); expect(webpackMock.compilerMock.run).to.have.been.calledOnce; return null; @@ -79,21 +81,22 @@ describe('compile', () => { it('should work with multi compile', () => { const testWebpackConfig = 'testconfig'; - const multiStats = [{ - compilation: { - errors: [], - compiler: { - outputPath: 'statsMock-outputPath', + const multiStats = [ + { + compilation: { + errors: [], + compiler: { + outputPath: 'statsMock-outputPath' + } }, - }, - toString: sandbox.stub().returns('testStats'), - }]; + toString: sandbox.stub().returns('testStats') + } + ]; module.webpackConfig = testWebpackConfig; module.multiCompile = true; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, multiStats); - return expect(module.compile()).to.be.fulfilled - .then(() => { + return expect(module.compile()).to.be.fulfilled.then(() => { expect(webpackMock).to.have.been.calledWith(testWebpackConfig); expect(webpackMock.compilerMock.run).to.have.been.calledOnce; return null; @@ -117,16 +120,17 @@ describe('compile', () => { module.webpackConfig = testWebpackConfig; webpackMock.compilerMock.run.reset(); webpackMock.compilerMock.run.yields(null, mockStats); - return (expect(module.compile()).to.be.fulfilled) - .then(() => { - expect(webpackMock).to.have.been.calledWith(testWebpackConfig); - expect(mockStats.toString.firstCall.args).to.eql([testWebpackConfig.stats]); - module.webpackConfig = [testWebpackConfig]; - return (expect(module.compile()).to.be.fulfilled); - }) - .then(() => { - expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); - expect(mockStats.toString.args).to.eql([[testWebpackConfig.stats], [testWebpackConfig.stats]]); - }); + return expect(module.compile()) + .to.be.fulfilled.then(() => { + expect(webpackMock).to.have.been.calledWith(testWebpackConfig); + expect(mockStats.toString.firstCall.args).to.eql([testWebpackConfig.stats]); + module.webpackConfig = [testWebpackConfig]; + return expect(module.compile()).to.be.fulfilled; + }) + .then(() => { + expect(webpackMock).to.have.been.calledWith([testWebpackConfig]); + expect(mockStats.toString.args).to.eql([ [testWebpackConfig.stats], [testWebpackConfig.stats] ]); + return null; + }); }); }); diff --git a/tests/mocks/fs.mock.js b/tests/mocks/fs.mock.js index 0682f4c85..8590528a3 100644 --- a/tests/mocks/fs.mock.js +++ b/tests/mocks/fs.mock.js @@ -19,9 +19,9 @@ module.exports.create = sandbox => { const streamMock = StreamMock(sandbox); const statMock = StatMock(sandbox); const fsMock = { - createWriteStream: sinon.stub().returns(streamMock), // Persistent stub + createWriteStream: sinon.stub().returns(streamMock), // Persistent stub readFileSync: sandbox.stub(), - statSync: sinon.stub().returns(statMock), // Persistent stub + statSync: sinon.stub().returns(statMock), // Persistent stub writeFileSync: sandbox.stub(), _streamMock: streamMock, diff --git a/tests/packExternalModules.test.js b/tests/packExternalModules.test.js index 0ed594f80..2fb9a88f3 100644 --- a/tests/packExternalModules.test.js +++ b/tests/packExternalModules.test.js @@ -40,7 +40,7 @@ const packagerMockFactory = { create(sandbox) { const packagerMock = { lockfileName: 'mocked-lock.json', - copyPackageSectionNames: ['section1', 'section2'], + copyPackageSectionNames: [ 'section1', 'section2' ], mustCopyModules: true, rebaseLockfile: sandbox.stub(), getProdDependencies: sandbox.stub(), @@ -107,17 +107,20 @@ describe('packExternalModules', () => { readFileSyncStub = sandbox.stub(serverless.utils, 'readFileSync'); _.set(serverless, 'service.custom.webpackIncludeModules', true); - module = _.assign({ - serverless, - options: { - verbose: true + module = _.assign( + { + serverless, + options: { + verbose: true + }, + configuration: new Configuration({ + webpack: { + includeModules: true + } + }) }, - configuration: new Configuration({ - webpack: { - includeModules: true - } - }) - }, baseModule); + baseModule + ); }); afterEach(() => { @@ -157,11 +160,9 @@ describe('packExternalModules', () => { }, { identifier: _.constant('external "bluebird"') - }, - ]), - new ChunkMockNoModulesIterable([ - + } ]), + new ChunkMockNoModulesIterable([]) ], compiler: { outputPath: '/my/Service/Path/.webpack/service' @@ -187,7 +188,7 @@ describe('packExternalModules', () => { }, { identifier: _.constant('"@scoped/vendor/module1"') - }, + } ]) ], compiler: { @@ -226,7 +227,7 @@ describe('packExternalModules', () => { }, { identifier: _.constant('external "bluebird"') - }, + } ]) ], compiler: { @@ -268,7 +269,7 @@ describe('packExternalModules', () => { }, { identifier: _.constant('external "bluebird"') - }, + } ]) ], compiler: { @@ -310,7 +311,7 @@ describe('packExternalModules', () => { }, { identifier: _.constant('external "aws-sdk"') - }, + } ]) ], compiler: { @@ -324,12 +325,13 @@ describe('packExternalModules', () => { it('should do nothing if webpackIncludeModules is not set', () => { module.configuration = new Configuration(); module.compileStats = { stats: [] }; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ expect(fsExtraMock.copy).to.not.have.been.called, expect(packagerFactoryMock.get).to.not.have.been.called, - expect(writeFileSyncStub).to.not.have.been.called, - ])); + expect(writeFileSyncStub).to.not.have.been.called + ]) + ); }); it('should copy needed package sections if available', () => { @@ -385,8 +387,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledTwice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -397,8 +399,9 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should install external modules', () => { @@ -435,8 +438,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledTwice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -447,8 +450,9 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should rebase file references', () => { @@ -521,23 +525,28 @@ describe('packExternalModules', () => { sandbox.stub(process, 'cwd').returns(path.join('/my/Service/Path')); mockery.registerMock(path.join(process.cwd(), 'locals', 'package.json'), packageLocalRefMock); - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ - // The module package JSON and the composite one should have been stored - expect(writeFileSyncStub).to.have.been.calledThrice, - expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), - expect(writeFileSyncStub.thirdCall.args[1]).to.equal(JSON.stringify(expectedPackageJSON, null, 2)), - // The modules and the lock file should have been copied - expect(fsExtraMock.copy).to.have.been.calledTwice, - // Lock file rebase should have been called - expect(packagerMock.rebaseLockfile).to.have.been.calledOnce, - expect(packagerMock.rebaseLockfile).to.have.been.calledWith(sinon.match.any, sinon.match(fakePackageLockJSON)), - // npm ls and npm prune should have been called - expect(packagerMock.getProdDependencies).to.have.been.calledOnce, - expect(packagerMock.install).to.have.been.calledOnce, - expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])) + return expect(module.packExternalModules()) + .to.be.fulfilled.then(() => + BbPromise.all([ + // The module package JSON and the composite one should have been stored + expect(writeFileSyncStub).to.have.been.calledThrice, + expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), + expect(writeFileSyncStub.thirdCall.args[1]).to.equal(JSON.stringify(expectedPackageJSON, null, 2)), + // The modules and the lock file should have been copied + expect(fsExtraMock.copy).to.have.been.calledTwice, + // Lock file rebase should have been called + expect(packagerMock.rebaseLockfile).to.have.been.calledOnce, + expect(packagerMock.rebaseLockfile).to.have.been.calledWith( + sinon.match.any, + sinon.match(fakePackageLockJSON) + ), + // npm ls and npm prune should have been called + expect(packagerMock.getProdDependencies).to.have.been.calledOnce, + expect(packagerMock.install).to.have.been.calledOnce, + expect(packagerMock.prune).to.have.been.calledOnce, + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ) .finally(() => { process.cwd.restore(); }); @@ -578,8 +587,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledTwice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -590,8 +599,9 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.not.have.been.called, - expect(packagerMock.runScripts).to.not.have.been.called, - ])); + expect(packagerMock.runScripts).to.not.have.been.called + ]) + ); }); it('should reject if packager install fails', () => { @@ -603,14 +613,17 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.rejectedWith('npm install failed') - .then(() => BbPromise.all([ - // npm ls and npm install should have been called - expect(packagerMock.getProdDependencies).to.have.been.calledOnce, - expect(packagerMock.install).to.have.been.calledOnce, - expect(packagerMock.prune).to.not.have.been.called, - expect(packagerMock.runScripts).to.not.have.been.called, - ])); + return expect(module.packExternalModules()) + .to.be.rejectedWith('npm install failed') + .then(() => + BbPromise.all([ + // npm ls and npm install should have been called + expect(packagerMock.getProdDependencies).to.have.been.calledOnce, + expect(packagerMock.install).to.have.been.calledOnce, + expect(packagerMock.prune).to.not.have.been.called, + expect(packagerMock.runScripts).to.not.have.been.called + ]) + ); }); it('should reject if packager returns a critical error', () => { @@ -619,18 +632,21 @@ describe('packExternalModules', () => { fsExtraMock.copy.yields(); packagerMock.getProdDependencies.callsFake(() => BbPromise.reject(new Error('something went wrong'))); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.rejectedWith('something went wrong') - .then(() => BbPromise.all([ - // The module package JSON and the composite one should have been stored - expect(writeFileSyncStub).to.not.have.been.called, - // The modules should have been copied - expect(fsExtraMock.copy).to.not.have.been.called, - // npm ls and npm prune should have been called - expect(packagerMock.getProdDependencies).to.have.been.calledOnce, - expect(packagerMock.install).to.not.have.been.called, - expect(packagerMock.prune).to.not.have.been.called, - expect(packagerMock.runScripts).to.not.have.been.called, - ])); + return expect(module.packExternalModules()) + .to.be.rejectedWith('something went wrong') + .then(() => + BbPromise.all([ + // The module package JSON and the composite one should have been stored + expect(writeFileSyncStub).to.not.have.been.called, + // The modules should have been copied + expect(fsExtraMock.copy).to.not.have.been.called, + // npm ls and npm prune should have been called + expect(packagerMock.getProdDependencies).to.have.been.calledOnce, + expect(packagerMock.install).to.not.have.been.called, + expect(packagerMock.prune).to.not.have.been.called, + expect(packagerMock.runScripts).to.not.have.been.called + ]) + ); }); it('should not install modules if no external modules are reported', () => { @@ -638,8 +654,8 @@ describe('packExternalModules', () => { fsExtraMock.copy.yields(); packagerMock.getProdDependencies.returns(BbPromise.resolve()); module.compileStats = noExtStats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.not.have.been.called, // The modules should have been copied @@ -648,31 +664,30 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.not.have.been.called, expect(packagerMock.prune).to.not.have.been.called, - expect(packagerMock.runScripts).to.not.have.been.called, - ])); + expect(packagerMock.runScripts).to.not.have.been.called + ]) + ); }); it('should report ignored packager problems in verbose mode', () => { module.webpackOutputPath = 'outputPath'; fsExtraMock.pathExists.yields(null, false); fsExtraMock.copy.yields(); - packagerMock.getProdDependencies.returns(BbPromise.resolve({ - problems: [ - 'Problem 1', - 'Problem 2' - ] - })); + packagerMock.getProdDependencies.returns( + BbPromise.resolve({ + problems: [ 'Problem 1', 'Problem 2' ] + }) + ); packagerMock.install.returns(BbPromise.resolve()); packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => { - expect(packagerMock.getProdDependencies).to.have.been.calledOnce; - expect(serverless.cli.log).to.have.been.calledWith('=> Problem 1'); - expect(serverless.cli.log).to.have.been.calledWith('=> Problem 2'); - return null; - }); + return expect(module.packExternalModules()).to.be.fulfilled.then(() => { + expect(packagerMock.getProdDependencies).to.have.been.calledOnce; + expect(serverless.cli.log).to.have.been.calledWith('=> Problem 1'); + expect(serverless.cli.log).to.have.been.calledWith('=> Problem 2'); + return null; + }); }); it('should install external modules when forced', () => { @@ -717,8 +732,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledTwice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -729,8 +744,9 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should add forced external modules without version when not in production dependencies', () => { @@ -775,8 +791,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledTwice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -787,8 +803,9 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should exclude external modules when forced', () => { @@ -832,8 +849,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledTwice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -844,8 +861,9 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should reject if devDependency is required at runtime', () => { @@ -857,15 +875,20 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = statsWithDevDependency; - return expect(module.packExternalModules()).to.be.rejectedWith('Serverless-webpack dependency error: eslint.') - .then(() => BbPromise.all([ - expect(module.serverless.cli.log).to.have.been.calledWith(sinon.match(/ERROR: Runtime dependency 'eslint' found in devDependencies/)), - // npm ls and npm install should have been called - expect(packagerMock.getProdDependencies).to.have.been.calledOnce, - expect(packagerMock.install).to.not.have.been.called, - expect(packagerMock.prune).to.not.have.been.called, - expect(packagerMock.runScripts).to.not.have.been.called, - ])); + return expect(module.packExternalModules()) + .to.be.rejectedWith('Serverless-webpack dependency error: eslint.') + .then(() => + BbPromise.all([ + expect(module.serverless.cli.log).to.have.been.calledWith( + sinon.match(/ERROR: Runtime dependency 'eslint' found in devDependencies/) + ), + // npm ls and npm install should have been called + expect(packagerMock.getProdDependencies).to.have.been.calledOnce, + expect(packagerMock.install).to.not.have.been.called, + expect(packagerMock.prune).to.not.have.been.called, + expect(packagerMock.runScripts).to.not.have.been.called + ]) + ); }); it('should ignore aws-sdk if set only in devDependencies', () => { @@ -885,15 +908,18 @@ describe('packExternalModules', () => { packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = statsWithIgnoredDevDependency; mockery.registerMock(path.join(process.cwd(), 'ignoreDevDeps', 'package.json'), packageIgnoredDevDepsMock); - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ - expect(module.serverless.cli.log).to.have.been.calledWith(sinon.match(/INFO: Runtime dependency 'aws-sdk' found in devDependencies/)), + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(module.serverless.cli.log).to.have.been.calledWith( + sinon.match(/INFO: Runtime dependency 'aws-sdk' found in devDependencies/) + ), // npm ls and npm install should have been called expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should succeed if devDependency is required at runtime but forcefully excluded', () => { @@ -912,14 +938,15 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = statsWithDevDependency; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // npm ls and npm install should have been called expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should read package-lock if found', () => { @@ -959,8 +986,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledThrice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -972,8 +999,9 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should continue if package-lock cannot be read', () => { @@ -1012,8 +1040,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledTwice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -1024,8 +1052,9 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); it('should skip module copy if demanded by packager', () => { @@ -1063,20 +1092,22 @@ describe('packExternalModules', () => { packagerMock.runScripts.returns(BbPromise.resolve()); packagerMock.mustCopyModules = false; module.compileStats = stats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ - // The module package JSON and the composite one should have been stored - expect(writeFileSyncStub).to.have.been.calledTwice, - expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), - expect(writeFileSyncStub.secondCall.args[1]).to.equal(JSON.stringify(expectedPackageJSON, null, 2)), - // The modules should not have been copied - expect(fsExtraMock.copy).to.not.have.been.called, - // npm ls and npm prune should have been called - expect(packagerMock.getProdDependencies).to.have.been.calledOnce, - expect(packagerMock.install).to.have.been.calledOnce, - expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])) + return expect(module.packExternalModules()) + .to.be.fulfilled.then(() => + BbPromise.all([ + // The module package JSON and the composite one should have been stored + expect(writeFileSyncStub).to.have.been.calledTwice, + expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), + expect(writeFileSyncStub.secondCall.args[1]).to.equal(JSON.stringify(expectedPackageJSON, null, 2)), + // The modules should not have been copied + expect(fsExtraMock.copy).to.not.have.been.called, + // npm ls and npm prune should have been called + expect(packagerMock.getProdDependencies).to.have.been.calledOnce, + expect(packagerMock.install).to.have.been.calledOnce, + expect(packagerMock.prune).to.have.been.calledOnce, + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ) .finally(() => { packagerMock.mustCopyModules = true; }); @@ -1089,24 +1120,14 @@ describe('packExternalModules', () => { mockery.registerMock(path.join(process.cwd(), 'package.json'), peerDepPackageJson); // Mock request-promise package.json const rpPackageJson = require('./data/rp-package.json'); - const rpPackagePath = path.join( - process.cwd(), - 'node_modules', - 'request-promise', - 'package.json' - ); + const rpPackagePath = path.join(process.cwd(), 'node_modules', 'request-promise', 'package.json'); mockery.registerMock(rpPackagePath, rpPackageJson); }); after(() => { mockery.deregisterMock(path.join(process.cwd(), 'package.json')); mockery.registerMock(path.join(process.cwd(), 'package.json'), packageMock); - const rpPackagePath = path.join( - process.cwd(), - 'node_modules', - 'request-promise', - 'package.json' - ); + const rpPackagePath = path.join(process.cwd(), 'node_modules', 'request-promise', 'package.json'); mockery.deregisterMock(rpPackagePath); }); @@ -1179,8 +1200,8 @@ describe('packExternalModules', () => { packagerMock.prune.returns(BbPromise.resolve()); packagerMock.runScripts.returns(BbPromise.resolve()); module.compileStats = peerDepStats; - return expect(module.packExternalModules()).to.be.fulfilled - .then(() => BbPromise.all([ + return expect(module.packExternalModules()).to.be.fulfilled.then(() => + BbPromise.all([ // The module package JSON and the composite one should have been stored expect(writeFileSyncStub).to.have.been.calledTwice, expect(writeFileSyncStub.firstCall.args[1]).to.equal(JSON.stringify(expectedCompositePackageJSON, null, 2)), @@ -1191,10 +1212,10 @@ describe('packExternalModules', () => { expect(packagerMock.getProdDependencies).to.have.been.calledOnce, expect(packagerMock.install).to.have.been.calledOnce, expect(packagerMock.prune).to.have.been.calledOnce, - expect(packagerMock.runScripts).to.have.been.calledOnce, - ])); + expect(packagerMock.runScripts).to.have.been.calledOnce + ]) + ); }); }); }); }); - diff --git a/tests/packageModules.test.js b/tests/packageModules.test.js index 741ce501f..22464a158 100644 --- a/tests/packageModules.test.js +++ b/tests/packageModules.test.js @@ -69,10 +69,13 @@ describe('packageModules', () => { getServiceObjectStub = sandbox.stub(serverless.service, 'getServiceObject'); getVersionStub = sandbox.stub(serverless, 'getVersion'); - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); }); afterEach(() => { @@ -84,13 +87,14 @@ describe('packageModules', () => { describe('packageModules()', () => { it('should do nothing if no compile stats are available', () => { module.compileStats = { stats: [] }; - return expect(module.packageModules()).to.be.fulfilled - .then(() => BbPromise.all([ - expect(archiverMock.create).to.not.have.been.called, - expect(writeFileDirStub).to.not.have.been.called, - expect(fsMock.createWriteStream).to.not.have.been.called, - expect(globMock.sync).to.not.have.been.called - ])); + return expect(module.packageModules()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(archiverMock.create).to.not.have.been.called, + expect(writeFileDirStub).to.not.have.been.called, + expect(fsMock.createWriteStream).to.not.have.been.called, + expect(globMock.sync).to.not.have.been.called + ]) + ); }); describe('with service packaging', () => { @@ -113,9 +117,7 @@ describe('packageModules', () => { } ] }; - const files = [ - 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' - ]; + const files = [ 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' ]; const allFunctions = [ 'func1', 'func2' ]; const func1 = { handler: 'src/handler1', @@ -143,11 +145,16 @@ describe('packageModules', () => { const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); module.compileStats = stats; - return expect(module.packageModules()).to.be.fulfilled - .then(() => BbPromise.all([ - expect(func1).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath), - expect(func2).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath), - ])); + return expect(module.packageModules()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(func1) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactPath), + expect(func2) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactPath) + ]) + ); }); describe('with the Google provider', () => { @@ -180,9 +187,7 @@ describe('packageModules', () => { } ] }; - const files = [ - 'README.md', 'index.js' - ]; + const files = [ 'README.md', 'index.js' ]; const allFunctions = [ 'func1', 'func2' ]; const func1 = { handler: 'handler1', @@ -209,8 +214,11 @@ describe('packageModules', () => { const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); module.compileStats = stats; - return expect(module.packageModules()).to.be.fulfilled - .then(() => expect(serverless.service).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath)); + return expect(module.packageModules()).to.be.fulfilled.then(() => + expect(serverless.service) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactPath) + ); }); }); @@ -227,9 +235,7 @@ describe('packageModules', () => { } ] }; - const files = [ - 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' - ]; + const files = [ 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' ]; const allFunctions = [ 'func1', 'func2' ]; const func1 = { handler: 'src/handler1', @@ -256,24 +262,35 @@ describe('packageModules', () => { const expectedArtifactPath = path.join('.serverless', 'test-service.zip'); module.compileStats = stats; - return BbPromise.each([ '1.18.1', '2.17.0', '10.15.3', ], version => { + return BbPromise.each([ '1.18.1', '2.17.0', '10.15.3' ], version => { getVersionStub.returns(version); - return expect(module.packageModules()).to.be.fulfilled - .then(() => BbPromise.all([ - expect(func1).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath), - expect(func2).to.have.a.nested.property('package.artifact').that.equals(expectedArtifactPath), - ])); - }) - .then(() => BbPromise.each([ '1.17.0', '1.16.0-alpha', '1.15.3', ], version => { - getVersionStub.returns(version); - return expect(module.packageModules()).to.be.fulfilled - .then(() => BbPromise.all([ - expect(func1).to.have.a.nested.property('artifact').that.equals(expectedArtifactPath), - expect(func2).to.have.a.nested.property('artifact').that.equals(expectedArtifactPath), - expect(func1).to.have.a.nested.property('package.disable').that.is.true, - expect(func2).to.have.a.nested.property('package.disable').that.is.true, - ])); - })); + return expect(module.packageModules()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(func1) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactPath), + expect(func2) + .to.have.a.nested.property('package.artifact') + .that.equals(expectedArtifactPath) + ]) + ); + }).then(() => + BbPromise.each([ '1.17.0', '1.16.0-alpha', '1.15.3' ], version => { + getVersionStub.returns(version); + return expect(module.packageModules()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(func1) + .to.have.a.nested.property('artifact') + .that.equals(expectedArtifactPath), + expect(func2) + .to.have.a.nested.property('artifact') + .that.equals(expectedArtifactPath), + expect(func1).to.have.a.nested.property('package.disable').that.is.true, + expect(func2).to.have.a.nested.property('package.disable').that.is.true + ]) + ); + }) + ); }); it('should reject if no files are found', () => { @@ -339,9 +356,7 @@ describe('packageModules', () => { } ] }; - const files = [ - 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' - ]; + const files = [ 'README.md', 'src/handler1.js', 'src/handler1.js.map', 'src/handler2.js', 'src/handler2.js.map' ]; const allFunctions = [ 'func1', 'func2' ]; const func1 = { handler: 'src/handler1', @@ -361,7 +376,7 @@ describe('packageModules', () => { handlerFile: 'src/handler2.js', funcName: 'func2', func: func2 - }, + } ]; beforeEach(() => { @@ -387,11 +402,16 @@ describe('packageModules', () => { fsMock._statMock.isDirectory.returns(false); module.compileStats = stats; - return expect(module.packageModules()).to.be.fulfilled - .then(() => BbPromise.all([ - expect(func1).to.have.a.nested.property('package.artifact').that.equals(path.join('.serverless', 'func1.zip')), - expect(func2).to.have.a.nested.property('package.artifact').that.equals(path.join('.serverless', 'func2.zip')), - ])); + return expect(module.packageModules()).to.be.fulfilled.then(() => + BbPromise.all([ + expect(func1) + .to.have.a.nested.property('package.artifact') + .that.equals(path.join('.serverless', 'func1.zip')), + expect(func2) + .to.have.a.nested.property('package.artifact') + .that.equals(path.join('.serverless', 'func2.zip')) + ]) + ); }); }); }); diff --git a/tests/prepareStepOfflineInvoke.test.js b/tests/prepareStepOfflineInvoke.test.js index 91c651e85..7bdf87b2e 100644 --- a/tests/prepareStepOfflineInvoke.test.js +++ b/tests/prepareStepOfflineInvoke.test.js @@ -31,10 +31,13 @@ describe('prepareStepOfflineInvoke', () => { log: sandbox.stub() }; sandbox.stub(serverless.pluginManager, 'spawn'); - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); }); afterEach(() => { @@ -47,8 +50,7 @@ describe('prepareStepOfflineInvoke', () => { module.webpackOutputPath = '.'; module.serverless.service.package = {}; - return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled.then(() => { expect(module.serverless.service.package).to.have.a.property('individually').that.is.false; return null; }); @@ -62,8 +64,7 @@ describe('prepareStepOfflineInvoke', () => { individually: true }; - return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled.then(() => { expect(module.serverless.service.package).to.have.a.property('individually').that.is.false; return null; }); @@ -74,8 +75,7 @@ describe('prepareStepOfflineInvoke', () => { serverless.config.servicePath = 'myPath'; module.webpackOutputPath = '.'; - return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled.then(() => { expect(serverless.pluginManager.spawn).to.have.been.calledOnce; expect(serverless.pluginManager.spawn).to.have.been.calledWithExactly('webpack:validate'); return null; @@ -95,8 +95,7 @@ describe('prepareStepOfflineInvoke', () => { serverless.config.servicePath = '.'; module.webpackOutputPath = '.'; - return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled.then(() => { expect(serverless.service).to.have.a.nested.property('custom.stepFunctionsOffline.location', 'service'); return null; }); @@ -108,8 +107,7 @@ describe('prepareStepOfflineInvoke', () => { module.webpackOutputPath = '.'; _.set(module.serverless, 'service.custom.stepFunctionsOffline.location', 'myLocation'); - return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled.then(() => { expect(serverless.service).to.have.a.nested.property('custom.stepFunctionsOffline.location', 'myLocation'); return null; }); @@ -123,8 +121,7 @@ describe('prepareStepOfflineInvoke', () => { location: 'myLocation' }; - return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled - .then(() => { + return expect(module.prepareStepOfflineInvoke()).to.be.fulfilled.then(() => { expect(serverless.service).to.not.have.a.nested.property('custom.stepFunctionsOffline.location'); return null; }); diff --git a/tests/run.test.js b/tests/run.test.js index b8cd1d3f5..5efa2b83a 100644 --- a/tests/run.test.js +++ b/tests/run.test.js @@ -49,10 +49,13 @@ describe('run', () => { consoleLog: sandbox.stub() }; - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); chdirStub = sandbox.stub(process, 'chdir'); }); @@ -164,17 +167,21 @@ describe('run', () => { module.options['webpack-use-polling'] = true; watch(); - expect(webpackMock.compilerMock.watch).to.have.been.calledWith({ poll: 3000 }); + expect(webpackMock.compilerMock.watch).to.have.been.calledWith({ + poll: 3000 + }); }); it('should turn on polling and set the specified poll interval', () => { module.isWatching = false; const watch = module.watch.bind(module); webpackMock.compilerMock.watch = sandbox.stub().yields(null, {}); - const interval = module.options['webpack-use-polling'] = _.now() % 10000; + const interval = (module.options['webpack-use-polling'] = _.now() % 10000); watch(); - expect(webpackMock.compilerMock.watch).to.have.been.calledWith({ poll: interval }); + expect(webpackMock.compilerMock.watch).to.have.been.calledWith({ + poll: interval + }); }); }); }); diff --git a/tests/runPluginSupport.test.js b/tests/runPluginSupport.test.js index afe46f8da..a30a2bf1f 100644 --- a/tests/runPluginSupport.test.js +++ b/tests/runPluginSupport.test.js @@ -26,18 +26,16 @@ describe('runPluginSupport', () => { sandbox = sinon.createSandbox(); sandbox.usingPromise(BbPromise.Promise); - const pluginRunUtils = path.join( - '.', - 'plugins', - 'run', - 'utils' - ); + const pluginRunUtils = path.join('.', 'plugins', 'run', 'utils'); deployFunctionsToLocalEmulatorStub = sandbox.stub().resolves(); getLocalRootUrlStub = sandbox.stub(); mockery.enable({ warnOnUnregistered: false }); - mockery.registerMock(path.join(pluginRunUtils, 'deployFunctionsToLocalEmulator'), deployFunctionsToLocalEmulatorStub); + mockery.registerMock( + path.join(pluginRunUtils, 'deployFunctionsToLocalEmulator'), + deployFunctionsToLocalEmulatorStub + ); mockery.registerMock(path.join(pluginRunUtils, 'getLocalRootUrl'), getLocalRootUrlStub); baseModule = require('../lib/runPluginSupport'); Object.freeze(baseModule); @@ -55,10 +53,13 @@ describe('runPluginSupport', () => { consoleLog: sandbox.stub() }; - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); _.set(serverless, 'config.serverlessPath', '.'); @@ -80,14 +81,15 @@ describe('runPluginSupport', () => { _.set(module, 'webpackOutputPath', webpackOutputPath); _.unset(module, 'keepOutputDirectory'); - return expect(prepareRun()).to.be.fulfilled - .then(() => BbPromise.join( - expect(module.originalServicePath).to.equal(servicePath), - expect(module.originalWebpackOutputPath).to.equal(webpackOutputPath), - expect(module.keepOutputDirectory).to.be.true, - expect(serverless.config.servicePath).to.equal(path.join(webpackOutputPath, 'service')), - expect(chdirStub).to.have.been.calledWith(serverless.config.servicePath) - )); + return expect(prepareRun()).to.be.fulfilled.then(() => + BbPromise.join( + expect(module.originalServicePath).to.equal(servicePath), + expect(module.originalWebpackOutputPath).to.equal(webpackOutputPath), + expect(module.keepOutputDirectory).to.be.true, + expect(serverless.config.servicePath).to.equal(path.join(webpackOutputPath, 'service')), + expect(chdirStub).to.have.been.calledWith(serverless.config.servicePath) + ) + ); }); }); @@ -105,12 +107,13 @@ describe('runPluginSupport', () => { _.set(module, 'hooks[before:run:run]', sandbox.stub().resolves()); _.set(serverless, 'service', service); - return expect(watchRun()).to.be.fulfilled - .then(() => BbPromise.join( - expect(deployFunctionsToLocalEmulatorStub).to.have.been.calledOnce, - expect(getLocalRootUrlStub).to.have.been.calledOnce, - expect(deployFunctionsToLocalEmulatorStub).to.have.been.calledWith(service) - )); + return expect(watchRun()).to.be.fulfilled.then(() => + BbPromise.join( + expect(deployFunctionsToLocalEmulatorStub).to.have.been.calledOnce, + expect(getLocalRootUrlStub).to.have.been.calledOnce, + expect(deployFunctionsToLocalEmulatorStub).to.have.been.calledWith(service) + ) + ); }); }); }); diff --git a/tests/utils.mock.js b/tests/utils.mock.js index f38c37cc6..0b559f4c9 100644 --- a/tests/utils.mock.js +++ b/tests/utils.mock.js @@ -4,12 +4,12 @@ const sinon = require('sinon'); module.exports = () => ({ _resetSpies() { - for (let p in this) { + for (const p in this) { if (this.hasOwnProperty(p) && p !== '_resetSpies') { this[p].reset(); } } }, guid: sinon.stub().returns('testguid'), - purgeCache: sinon.spy(), + purgeCache: sinon.spy() }); diff --git a/tests/validate.test.js b/tests/validate.test.js index 15e87923f..df62757e1 100644 --- a/tests/validate.test.js +++ b/tests/validate.test.js @@ -46,10 +46,13 @@ describe('validate', () => { serverless.cli = { log: sandbox.stub() }; - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); }); afterEach(() => { @@ -67,13 +70,11 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: 'test', - }, + path: 'test' + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(module.webpackConfig).to.eql(testConfig)); + return module.validate().then(() => expect(module.webpackConfig).to.eql(testConfig)); }); it('should delete the output path', () => { @@ -82,13 +83,11 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(fsExtraMock.removeSync).to.have.been.calledWith(testOutPath)); + return module.validate().then(() => expect(fsExtraMock.removeSync).to.have.been.calledWith(testOutPath)); }); it('should keep the output path if requested', () => { @@ -97,14 +96,12 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module, 'keepOutputDirectory', true); _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(fsExtraMock.removeSync).to.not.have.been.called); + return module.validate().then(() => expect(fsExtraMock.removeSync).to.not.have.been.called); }); it('should override the output path if `out` option is specified', () => { @@ -113,61 +110,55 @@ describe('validate', () => { context: 'testcontext', output: { path: 'originalpath', - filename: 'filename', - }, + filename: 'filename' + } }; const testServicePath = 'testpath'; const testOptionsOut = 'testdir'; module.options.out = testOptionsOut; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(module.webpackConfig.output).to.eql({ + return module.validate().then(() => + expect(module.webpackConfig.output).to.eql({ path: path.join(testServicePath, testOptionsOut, 'service'), - filename: 'filename', - })); + filename: 'filename' + }) + ); }); it('should set a default `webpackConfig.context` if not present', () => { const testConfig = { entry: 'test', - output: {}, + output: {} }; const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(module.webpackConfig.context).to.equal(testServicePath)); + return module.validate().then(() => expect(module.webpackConfig.context).to.equal(testServicePath)); }); describe('default target', () => { it('should set a default `webpackConfig.target` if not present', () => { const testConfig = { entry: 'test', - output: {}, + output: {} }; const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(module.webpackConfig.target).to.equal('node')); + return module.validate().then(() => expect(module.webpackConfig.target).to.equal('node')); }); it('should not change `webpackConfig.target` if one is present', () => { const testConfig = { entry: 'test', target: 'myTarget', - output: {}, + output: {} }; const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(module.webpackConfig.target).to.equal('myTarget')); + return module.validate().then(() => expect(module.webpackConfig.target).to.equal('myTarget')); }); }); @@ -175,35 +166,35 @@ describe('validate', () => { it('should set a default `webpackConfig.output` if not present', () => { const testEntry = 'testentry'; const testConfig = { - entry: testEntry, + entry: testEntry }; const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(module.webpackConfig.output).to.eql({ + return module.validate().then(() => + expect(module.webpackConfig.output).to.eql({ libraryTarget: 'commonjs', path: path.join(testServicePath, '.webpack', 'service'), - filename: '[name].js', - })); + filename: '[name].js' + }) + ); }); it('should set a default `webpackConfig.output.filename` if `entry` is an array', () => { const testEntry = [ 'first', 'second', 'last' ]; const testConfig = { - entry: testEntry, + entry: testEntry }; const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(module.webpackConfig.output).to.eql({ + return module.validate().then(() => + expect(module.webpackConfig.output).to.eql({ libraryTarget: 'commonjs', path: path.join(testServicePath, '.webpack', 'service'), - filename: '[name].js', - })); + filename: '[name].js' + }) + ); }); it('should set a default `webpackConfig.output.filename` if `entry` is not defined', () => { @@ -211,13 +202,13 @@ describe('validate', () => { const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return module - .validate() - .then(() => expect(module.webpackConfig.output).to.eql({ + return module.validate().then(() => + expect(module.webpackConfig.output).to.eql({ libraryTarget: 'commonjs', path: path.join(testServicePath, '.webpack', 'service'), - filename: '[name].js', - })); + filename: '[name].js' + }) + ); }); }); @@ -230,18 +221,18 @@ describe('validate', () => { module.serverless.service.custom.webpack = testConfig; serverless.utils.fileExistsSync = sinon.stub().returns(true); const loadedConfig = { - entry: 'testentry', + entry: 'testentry' }; mockery.registerMock(requiredPath, loadedConfig); - return expect(module.validate()).to.fulfilled - .then(() => { - expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); - expect(module.webpackConfig).to.eql(loadedConfig); - return null; - }) - .finally(() => { - mockery.deregisterMock(requiredPath); - }); + return expect(module.validate()) + .to.fulfilled.then(() => { + expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); + expect(module.webpackConfig).to.eql(loadedConfig); + return null; + }) + .finally(() => { + mockery.deregisterMock(requiredPath); + }); }); it('should load a async webpack config from file if `custom.webpack` is a string', () => { @@ -252,19 +243,19 @@ describe('validate', () => { module.serverless.service.custom.webpack = testConfig; serverless.utils.fileExistsSync = sinon.stub().returns(true); const loadedConfig = { - entry: 'testentry', + entry: 'testentry' }; const loadedConfigPromise = BbPromise.resolve(loadedConfig); mockery.registerMock(requiredPath, loadedConfigPromise); - return expect(module.validate()).to.be.fulfilled - .then(() => { - expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); - expect(module.webpackConfig).to.deep.equal(loadedConfig); - return null; - }) - .finally(() => { - mockery.deregisterMock(requiredPath); - }); + return expect(module.validate()) + .to.be.fulfilled.then(() => { + expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); + expect(module.webpackConfig).to.deep.equal(loadedConfig); + return null; + }) + .finally(() => { + mockery.deregisterMock(requiredPath); + }); }); it('should catch errors while loading a async webpack config from file if `custom.webpack` is a string', () => { @@ -276,14 +267,15 @@ describe('validate', () => { serverless.utils.fileExistsSync = sinon.stub().returns(true); const loadedConfigPromise = BbPromise.reject('config failed to load'); mockery.registerMock(requiredPath, loadedConfigPromise); - return expect(module.validate()).to.be.rejectedWith('config failed to load') - .then(() => { - expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); - return null; - }) - .finally(() => { - mockery.deregisterMock(requiredPath); - }); + return expect(module.validate()) + .to.be.rejectedWith('config failed to load') + .then(() => { + expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); + return null; + }) + .finally(() => { + mockery.deregisterMock(requiredPath); + }); }); it('should load a wrong thenable webpack config as normal object from file if `custom.webpack` is a string', () => { @@ -295,18 +287,18 @@ describe('validate', () => { serverless.utils.fileExistsSync = sinon.stub().returns(true); const loadedConfig = { then: 'I am not a Promise member', - entry: 'testentry', + entry: 'testentry' }; mockery.registerMock(requiredPath, loadedConfig); - return expect(module.validate()).to.be.fulfilled - .then(() => { - expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); - expect(module.webpackConfig).to.deep.equal(loadedConfig); - return null; - }) - .finally(() => { - mockery.deregisterMock(requiredPath); - }); + return expect(module.validate()) + .to.be.fulfilled.then(() => { + expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); + expect(module.webpackConfig).to.deep.equal(loadedConfig); + return null; + }) + .finally(() => { + mockery.deregisterMock(requiredPath); + }); }); it('should throw if providing an invalid file', () => { @@ -325,18 +317,18 @@ describe('validate', () => { module.serverless.config.servicePath = testServicePath; serverless.utils.fileExistsSync = sinon.stub().returns(true); const loadedConfig = { - entry: 'testentry', + entry: 'testentry' }; mockery.registerMock(requiredPath, loadedConfig); - return expect(module.validate()).to.be.fulfilled - .then(() => { - expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); - expect(module.webpackConfig).to.eql(loadedConfig); - return null; - }) - .finally(() => { - mockery.deregisterMock(requiredPath); - }); + return expect(module.validate()) + .to.be.fulfilled.then(() => { + expect(serverless.utils.fileExistsSync).to.have.been.calledWith(requiredPath); + expect(module.webpackConfig).to.eql(loadedConfig); + return null; + }) + .finally(() => { + mockery.deregisterMock(requiredPath); + }); }); it('should fail when importing a broken configuration file', () => { @@ -345,8 +337,9 @@ describe('validate', () => { module.serverless.config.servicePath = testServicePath; module.serverless.service.custom.webpack = testConfig; serverless.utils.fileExistsSync = sinon.stub().returns(true); - return expect(module.validate()).to.be.rejected - .then(() => expect(serverless.cli.log).to.have.been.calledWith(sinon.match(/^Could not load webpack config/))); + return expect(module.validate()).to.be.rejected.then(() => + expect(serverless.cli.log).to.have.been.calledWith(sinon.match(/^Could not load webpack config/)) + ); }); }); @@ -357,12 +350,11 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); expect(lib.serverless).to.equal(serverless); return null; @@ -375,20 +367,22 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; const testOptions = { stage: 'testStage', verbose: true }; - const configuredModule = _.assign({ - serverless, - options: _.cloneDeep(testOptions), - }, baseModule); + const configuredModule = _.assign( + { + serverless, + options: _.cloneDeep(testOptions) + }, + baseModule + ); _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return expect(configuredModule.validate()).to.be.fulfilled - .then(() => { + return expect(configuredModule.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); expect(lib.options).to.deep.equal(testOptions); return null; @@ -406,12 +400,14 @@ describe('validate', () => { func1: { handler: 'module1.func1handler', artifact: 'artifact-func1.zip', - events: [{ - http: { - method: 'get', - path: 'func1path', - }, - }], + events: [ + { + http: { + method: 'get', + path: 'func1path' + } + } + ] }, func2: { handler: 'module2.func2handler', @@ -420,39 +416,46 @@ describe('validate', () => { { http: { method: 'POST', - path: 'func2path', - }, - }, { - nonhttp: 'non-http', + path: 'func2path' + } + }, + { + nonhttp: 'non-http' } - ], + ] }, func3: { handler: 'handlers/func3/module2.func3handler', artifact: 'artifact-func3.zip', - events: [{ - nonhttp: 'non-http', - }], + events: [ + { + nonhttp: 'non-http' + } + ] }, func4: { handler: 'handlers/module2/func3/module2.func3handler', artifact: 'artifact-func3.zip', - events: [{ - nonhttp: 'non-http', - }], - }, + events: [ + { + nonhttp: 'non-http' + } + ] + } }; const testFunctionsGoogleConfig = { func1: { handler: 'func1handler', - events: [{ - http: { - method: 'get', - path: 'func1path', - }, - }], - }, + events: [ + { + http: { + method: 'get', + path: 'func1path' + } + } + ] + } }; it('should expose all functions if `options.function` is not defined', () => { @@ -461,20 +464,19 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsConfig; globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); const expectedLibEntries = { - 'module1': './module1.js', - 'module2': './module2.js', + module1: './module1.js', + module2: './module2.js', 'handlers/func3/module2': './handlers/func3/module2.js', - 'handlers/module2/func3/module2': './handlers/module2/func3/module2.js', + 'handlers/module2/func3/module2': './handlers/module2/func3/module2.js' }; expect(lib.entries).to.deep.equal(expectedLibEntries); @@ -491,18 +493,17 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsConfig; module.options.function = testFunction; globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); const expectedLibEntries = { - 'module1': './module1.js' + module1: './module1.js' }; expect(lib.entries).to.deep.equal(expectedLibEntries); @@ -515,7 +516,6 @@ describe('validate', () => { describe('google provider', () => { beforeEach(() => { _.set(module.serverless, 'service.provider.name', 'google'); - }); afterEach(() => { @@ -531,14 +531,13 @@ describe('validate', () => { output: { path: testOutPath, filename: 'index.js' - }, + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsGoogleConfig; module.options.function = testFunction; globSyncStub.returns([]); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); expect(lib.entries).to.deep.equal({}); @@ -552,8 +551,8 @@ describe('validate', () => { describe('package individually', () => { const testConfig = { output: { - path: 'output', - }, + path: 'output' + } }; beforeEach(() => { @@ -570,8 +569,7 @@ describe('validate', () => { globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); expect(module.multiCompile).to.be.undefined; - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { expect(module.multiCompile).to.be.true; return null; @@ -579,23 +577,32 @@ describe('validate', () => { }); it('should fail if webpackConfig.entry is customised', () => { - _.set(module.serverless.service, 'custom.webpack.config', _.merge({}, testConfig, { - entry: { - module1: './module1.js', - module2: './module2.js' - } - })); + _.set( + module.serverless.service, + 'custom.webpack.config', + _.merge({}, testConfig, { + entry: { + module1: './module1.js', + module2: './module2.js' + } + }) + ); module.serverless.service.functions = testFunctionsConfig; globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); return expect(module.validate()).to.be.rejectedWith( - /Webpack entry must be automatically resolved when package.individually is set to true/); + /Webpack entry must be automatically resolved when package.individually is set to true/ + ); }); it('should not fail if webpackConfig.entry is set to lib.entries for backward compatibility', () => { const lib = require('../lib/index'); - _.set(module.serverless.service, 'custom.webpack.config', _.merge({}, testConfig, { - entry: lib.entries - })); + _.set( + module.serverless.service, + 'custom.webpack.config', + _.merge({}, testConfig, { + entry: lib.entries + }) + ); module.serverless.service.functions = testFunctionsConfig; globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); return expect(module.validate()).to.be.fulfilled; @@ -605,8 +612,7 @@ describe('validate', () => { _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsConfig; globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { expect(module.entryFunctions).to.deep.equal([ { handlerFile: 'module1', @@ -624,13 +630,19 @@ describe('validate', () => { handlerFile: path.join('handlers', 'func3', 'module2'), funcName: 'func3', func: testFunctionsConfig.func3, - entry: { key: 'handlers/func3/module2', value: './handlers/func3/module2.js' } + entry: { + key: 'handlers/func3/module2', + value: './handlers/func3/module2.js' + } }, { handlerFile: path.join('handlers', 'module2', 'func3', 'module2'), funcName: 'func4', func: testFunctionsConfig.func4, - entry: { key: 'handlers/module2/func3/module2', value: './handlers/module2/func3/module2.js' } + entry: { + key: 'handlers/module2/func3/module2', + value: './handlers/module2/func3/module2.js' + } } ]); return null; @@ -641,8 +653,7 @@ describe('validate', () => { _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsConfig; globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { expect(module.webpackConfig).to.have.lengthOf(4); expect(module.webpackConfig[0].output.path).to.equal(path.join('output', 'func1')); expect(module.webpackConfig[1].output.path).to.equal(path.join('output', 'func2')); @@ -654,17 +665,20 @@ describe('validate', () => { }); it('should clone other webpackConfig options without modification', () => { - _.set(module.serverless.service, 'custom.webpack.config', _.merge({}, testConfig, { - devtool: 'source-map', - context: 'some context', - output: { - libraryTarget: 'commonjs' - } - })); + _.set( + module.serverless.service, + 'custom.webpack.config', + _.merge({}, testConfig, { + devtool: 'source-map', + context: 'some context', + output: { + libraryTarget: 'commonjs' + } + }) + ); module.serverless.service.functions = testFunctionsConfig; globSyncStub.callsFake(filename => [_.replace(filename, '*', 'js')]); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { expect(module.webpackConfig).to.have.lengthOf(4); expect(module.webpackConfig[0].devtool).to.equal('source-map'); expect(module.webpackConfig[1].devtool).to.equal('source-map'); @@ -690,25 +704,24 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsConfig; module.options.function = testFunction; globSyncStub.returns([ 'module1.ts', 'module1.js' ]); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); const expectedLibEntries = { - 'module1': './module1.ts' + module1: './module1.ts' }; expect(lib.entries).to.deep.equal(expectedLibEntries); expect(globSyncStub).to.have.been.calledOnce; expect(serverless.cli.log).to.have.been.calledOnce; expect(serverless.cli.log).to.have.been.calledWith( - 'WARNING: More than one matching handlers found for \'module1\'. Using \'module1.ts\'.' + "WARNING: More than one matching handlers found for 'module1'. Using 'module1.ts'." ); return null; }); @@ -721,25 +734,24 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsConfig; module.options.function = testFunction; globSyncStub.returns([ 'module1.doc', 'module1.json', 'module1.test.js', 'module1.ts', 'module1.js' ]); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); const expectedLibEntries = { - 'module1': './module1.ts' + module1: './module1.ts' }; expect(lib.entries).to.deep.equal(expectedLibEntries); expect(globSyncStub).to.have.been.calledOnce; expect(serverless.cli.log).to.have.been.calledOnce; expect(serverless.cli.log).to.have.been.calledWith( - 'WARNING: More than one matching handlers found for \'module1\'. Using \'module1.ts\'.' + "WARNING: More than one matching handlers found for 'module1'. Using 'module1.ts'." ); return null; }); @@ -752,19 +764,18 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); _.set(module.serverless.service, 'custom.webpack.excludeFiles', '**/*.ts'); module.serverless.service.functions = testFunctionsConfig; module.options.function = testFunction; globSyncStub.returns(['module1.js']); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); const expectedLibEntries = { - 'module1': './module1.js' + module1: './module1.js' }; expect(lib.entries).to.deep.equal(expectedLibEntries); @@ -786,8 +797,8 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsConfig; @@ -805,8 +816,8 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.serverless.service.functions = testFunctionsConfig; @@ -824,12 +835,11 @@ describe('validate', () => { entry: 'test', context: 'testcontext', output: { - path: testOutPath, - }, + path: testOutPath + } }; _.set(module.serverless.service, 'custom.webpack.config', testConfig); - return expect(module.validate()).to.be.fulfilled - .then(() => { + return expect(module.validate()).to.be.fulfilled.then(() => { const lib = require('../lib/index'); expect(lib.webpack.isLocal).to.be.false; return null; @@ -842,16 +852,14 @@ describe('validate', () => { it('should keep output directory', () => { const testConfig = { entry: 'test', - output: {}, + output: {} }; const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; _.set(module.serverless.service, 'custom.webpack.config', testConfig); module.skipCompile = true; fsExtraMock.pathExistsSync.returns(true); - return module - .validate() - .then(() => { + return module.validate().then(() => { expect(module.keepOutputDirectory).to.be.true; return null; }); @@ -860,7 +868,7 @@ describe('validate', () => { it('should fail without exiting output', () => { const testConfig = { entry: 'test', - output: {}, + output: {} }; const testServicePath = 'testpath'; module.serverless.config.servicePath = testServicePath; diff --git a/tests/webpack.mock.js b/tests/webpack.mock.js index 9f8f124d6..abf911e6b 100644 --- a/tests/webpack.mock.js +++ b/tests/webpack.mock.js @@ -6,13 +6,12 @@ const StatsMock = () => ({ compilation: { errors: [], compiler: { - outputPath: 'statsMock-outputPath', - }, + outputPath: 'statsMock-outputPath' + } }, - toString: sinon.stub().returns('testStats'), + toString: sinon.stub().returns('testStats') }); - const CompilerMock = (sandbox, statsMock) => ({ run: sandbox.stub().yields(null, statsMock), watch: sandbox.stub().yields(null, statsMock), @@ -20,7 +19,7 @@ const CompilerMock = (sandbox, statsMock) => ({ beforeCompile: { tapPromise: sandbox.stub() } - }, + } }); const webpackMock = sandbox => { diff --git a/tests/wpwatch.test.js b/tests/wpwatch.test.js index 05afb0505..bb21a4910 100644 --- a/tests/wpwatch.test.js +++ b/tests/wpwatch.test.js @@ -51,10 +51,13 @@ describe('wpwatch', function() { consoleLog: sandbox.stub() }; - module = _.assign({ - serverless, - options: {}, - }, baseModule); + module = _.assign( + { + serverless, + options: {} + }, + baseModule + ); spawnStub = sandbox.stub(serverless.pluginManager, 'spawn'); @@ -83,11 +86,12 @@ describe('wpwatch', function() { spawnStub.resolves(); _.set(module.options, 'webpack-no-watch', true); - return expect(wpwatch()).to.be.fulfilled - .then(() => BbPromise.join( - expect(spawnStub).to.have.been.calledWith('webpack:compile'), - expect(webpackMock.compilerMock.watch).to.not.have.been.called - )); + return expect(wpwatch()).to.be.fulfilled.then(() => + BbPromise.join( + expect(spawnStub).to.have.been.calledWith('webpack:compile'), + expect(webpackMock.compilerMock.watch).to.not.have.been.called + ) + ); }); it('should enter watch mode and return after first compile', () => { @@ -95,36 +99,38 @@ describe('wpwatch', function() { webpackMock.compilerMock.watch.yields(null, {}); spawnStub.resolves(); - return expect(wpwatch()).to.be.fulfilled - .then(() => BbPromise.join( - expect(spawnStub).to.not.have.been.called, - expect(webpackMock.compilerMock.watch).to.have.been.calledOnce - )); + return expect(wpwatch()).to.be.fulfilled.then(() => + BbPromise.join( + expect(spawnStub).to.not.have.been.called, + expect(webpackMock.compilerMock.watch).to.have.been.calledOnce + ) + ); }); it('should still enter watch mode and return if lastHash is the same as previous', () => { const wpwatch = module.wpwatch.bind(module); webpackMock.compilerMock.watch.yields(null, { hash: null }); - return expect(wpwatch()).to.be.fulfilled - .then(() => BbPromise.join( + return expect(wpwatch()).to.be.fulfilled.then(() => + BbPromise.join( expect(spawnStub).to.not.have.been.called, expect(webpackMock.compilerMock.watch).to.have.been.calledOnce, expect(spawnStub).to.not.have.been.called - )); + ) + ); }); - it('should work if no stats are returned', () => { const wpwatch = module.wpwatch.bind(module); webpackMock.compilerMock.watch.yields(); spawnStub.resolves(); - return expect(wpwatch()).to.be.fulfilled - .then(() => BbPromise.join( - expect(spawnStub).to.not.have.been.called, - expect(webpackMock.compilerMock.watch).to.have.been.calledOnce - )); + return expect(wpwatch()).to.be.fulfilled.then(() => + BbPromise.join( + expect(spawnStub).to.not.have.been.called, + expect(webpackMock.compilerMock.watch).to.have.been.calledOnce + ) + ); }); it('should enable polling with command line switch', () => { @@ -133,12 +139,15 @@ describe('wpwatch', function() { spawnStub.resolves(); _.set(module.options, 'webpack-use-polling', true); - return expect(wpwatch()).to.be.fulfilled - .then(() => BbPromise.join( - expect(spawnStub).to.not.have.been.called, - expect(webpackMock.compilerMock.watch).to.have.been.calledOnce, - expect(webpackMock.compilerMock.watch).to.have.been.calledWith({ poll: 3000 }) - )); + return expect(wpwatch()).to.be.fulfilled.then(() => + BbPromise.join( + expect(spawnStub).to.not.have.been.called, + expect(webpackMock.compilerMock.watch).to.have.been.calledOnce, + expect(webpackMock.compilerMock.watch).to.have.been.calledWith({ + poll: 3000 + }) + ) + ); }); it('should set specific polling interval if given with switch', () => { @@ -147,12 +156,15 @@ describe('wpwatch', function() { spawnStub.resolves(); _.set(module.options, 'webpack-use-polling', 5000); - return expect(wpwatch()).to.be.fulfilled - .then(() => BbPromise.join( - expect(spawnStub).to.not.have.been.called, - expect(webpackMock.compilerMock.watch).to.have.been.calledOnce, - expect(webpackMock.compilerMock.watch).to.have.been.calledWith({ poll: 5000 }) - )); + return expect(wpwatch()).to.be.fulfilled.then(() => + BbPromise.join( + expect(spawnStub).to.not.have.been.called, + expect(webpackMock.compilerMock.watch).to.have.been.calledOnce, + expect(webpackMock.compilerMock.watch).to.have.been.calledWith({ + poll: 5000 + }) + ) + ); }); it('should spawn webpack:compile:watch on subsequent runs', () => { @@ -178,8 +190,8 @@ describe('wpwatch', function() { watchCallbackSpy(null, { call: 3, hash: '4' }); }); - return expect(wpwatch()).to.be.fulfilled.then( - () => BbPromise.join( + return expect(wpwatch()).to.be.fulfilled.then(() => + BbPromise.join( expect(watchCallbackSpy).to.have.been.callCount(4), expect(spawnStub).to.have.been.calledOnce, expect(spawnStub).to.have.been.calledWithExactly('webpack:compile:watch') @@ -211,25 +223,27 @@ describe('wpwatch', function() { }); }); - return expect(wpwatch()).to.be.fulfilled - .then(() => beforeCompileCallbackSpyPromise) - .then(() => BbPromise.join( - expect(watchCallbackSpy).to.have.been.calledThrice, - expect(spawnStub).to.have.been.calledTwice, - expect(spawnStub).to.have.been.calledWithExactly('webpack:compile:watch') - )); + return expect(wpwatch()) + .to.be.fulfilled.then(() => beforeCompileCallbackSpyPromise) + .then(() => + BbPromise.join( + expect(watchCallbackSpy).to.have.been.calledThrice, + expect(spawnStub).to.have.been.calledTwice, + expect(spawnStub).to.have.been.calledWithExactly('webpack:compile:watch') + ) + ); }); - it('should use plugins for webpack:compile:watch if hooks doesn\'t exist', () => { + it("should use plugins for webpack:compile:watch if hooks doesn't exist", () => { const wpwatch = module.wpwatch.bind(module); sandbox.stub(webpackMock.compilerMock, 'hooks').value(false); webpackMock.compilerMock.plugin = sandbox.stub().yields(null, _.noop); webpackMock.compilerMock.watch.yields(null, {}); - return expect(wpwatch()).to.be.fulfilled.then(() => ( - expect(webpackMock.compilerMock.plugin).to.have.been.calledOnce - )); + return expect(wpwatch()).to.be.fulfilled.then( + () => expect(webpackMock.compilerMock.plugin).to.have.been.calledOnce + ); }); it('should not resolve before compile if it has an error', () => { @@ -253,9 +267,7 @@ describe('wpwatch', function() { }); }); - return expect(wpwatch()).to.be.fulfilled.then(() => ( - expect(doesResolve).to.be.false - )); + return expect(wpwatch()).to.be.fulfilled.then(() => expect(doesResolve).to.be.false); }); it('should throw if compile fails on subsequent runs', () => { @@ -272,10 +284,11 @@ describe('wpwatch', function() { watchCallbackSpy(new Error('Compile failed')); }); - return expect(wpwatch()).to.be.fulfilled - .then(() => BbPromise.join( - expect(watchCallbackSpy).to.have.been.calledTwice, - expect(watchCallbackSpy.secondCall.threw()).to.be.true - )); + return expect(wpwatch()).to.be.fulfilled.then(() => + BbPromise.join( + expect(watchCallbackSpy).to.have.been.calledTwice, + expect(watchCallbackSpy.secondCall.threw()).to.be.true + ) + ); }); });