diff --git a/CHANGELOG.md b/CHANGELOG.md index 995833626..4e3c458bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# 1.17.0 (05.07.2017) +- Cleanup F# build template output on macOS - #3897 +- Add disable flag for OpenWhisk functions - #3830 +- Only redeploy when the code/config changes - #3838 +- Add opt-out config for dev dependency exclusion - #3877 +- Add infinite stack trace for errors - #3839 +- Fixed a bug with autocomplete - #3798 + + +## Meta +- [Comparison since last release](https://github.com/serverless/serverless/compare/v1.16.1...v1.17.0) + + # 1.16.1 (26.06.2017) - CI/CD fix for the Serverless Platform - #3829 diff --git a/README.md b/README.md index 535802fe5..f721d4c9f 100644 --- a/README.md +++ b/README.md @@ -313,6 +313,7 @@ These consultants use the Serverless Framework and can help you build your serve * [EPX Labs](http://www.epxlabs.com/) - runs [Serverless NYC Meetup](https://www.meetup.com/Serverless-NYC/) * [Red Badger](https://red-badger.com) * [Langa](http://langa.io/?utm_source=gh-serverless&utm_medium=github) - They built [Trails.js](http://github.com/trailsjs/trails) +* [Emerging Technology Advisors](https://www.emergingtechnologyadvisors.com) ---- diff --git a/docs/README.md b/docs/README.md index fa2c1f0bb..16b983d67 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,9 +18,9 @@ menuItems: The Serverless Framework is a CLI tool that allows users to build & deploy auto-scaling, pay-per-execution, event-driven functions. -Write your code, configure events to trigger your functions, then deploy & run those functions to your [cloud provider](#Supported-Providers) via the **serverless CLI**. +Write your code, configure events to trigger your functions, then deploy & run those functions to your [cloud provider](#Supported-Providers) via the **Serverless CLI**. -Getting started with serverless? **[Start here](./getting-started.md)** +Getting started with serverless? **[Start here](./getting-started.md)**. Already using AWS or another cloud provider? Read on. diff --git a/docs/providers/aws/events/s3.md b/docs/providers/aws/events/s3.md index 673fd7c78..52f263e00 100644 --- a/docs/providers/aws/events/s3.md +++ b/docs/providers/aws/events/s3.md @@ -73,3 +73,41 @@ functions: bucket: photos event: s3:ObjectRemoved:* ``` + +## Custom bucket configuration + +If you need to configure the bucket itself, you'll need to create the bucket and the Lambda Permission manually in +the Resources section while paying attention to some of the logical IDs. This relies on the Serverless naming convention. See the [Serverless Resource Reference](../guide/resources.md#aws-cloudformation-resource-reference) for details. These are the logical IDs that require your attention: +- The logical ID of the custom bucket in the Resources section needs to match the bucket name in the S3 event after the Serverless naming convention is applied to it. +- The Lambda Permission's logical ID needs to match the Serverless naming convention for Lambda Permissions for S3 events. +- The `FunctionName` in the Lambda Permission configuration needs to match the logical ID generated for the target Lambda function as determined by the Serverless naming convention. + +The following example will work: + +```yaml +functions: + resize: + handler: resize.handler + events: + - s3: photos + +resources: + Resources: + S3BucketPhotos: + Type: AWS::S3::Bucket + Properties: + BucketName: my-custom-bucket-name + # add additional custom bucket configuration here + ResizeLambdaPermissionPhotosS3: + Type: "AWS::Lambda::Permission" + Properties: + FunctionName: + "Fn::GetAtt": + - ResizeLambdaFunction + - Arn + Principal: "s3.amazonaws.com" + Action: "lambda:InvokeFunction" + SourceAccount: + Ref: AWS::AccountId + SourceArn: "arn:aws:s3:::my-custom-bucket-name" +``` diff --git a/docs/providers/aws/guide/deploying.md b/docs/providers/aws/guide/deploying.md index e412ccc1a..eb1a99be8 100644 --- a/docs/providers/aws/guide/deploying.md +++ b/docs/providers/aws/guide/deploying.md @@ -24,6 +24,8 @@ serverless deploy Use this method when you have updated your Function, Event or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to Amazon Web Services. +**Note:** You can always enforce a deployment using the `--force` option. + ### How It Works The Serverless Framework translates all syntax in `serverless.yml` to a single AWS CloudFormation template. By depending on CloudFormation for deployments, users of the Serverless Framework get the safety and reliability of CloudFormation. @@ -31,6 +33,8 @@ The Serverless Framework translates all syntax in `serverless.yml` to a single A * An AWS CloudFormation template is created from your `serverless.yml`. * If a Stack has not yet been created, then it is created with no resources except for an S3 Bucket, which will store zip files of your Function code. * The code of your Functions is then packaged into zip files. +* Serverless fetches the hashes for all files of the previous deployment (if any) and compares them against the hashes of the local files. +* Serverless terminates the deployment process if all file hashes are the same. * Zip files of your Functions' code are uploaded to your Code S3 Bucket. * Any IAM Roles, Functions, Events and Resources are added to the AWS CloudFormation template. * The CloudFormation Stack is updated with the new CloudFormation template. @@ -74,9 +78,13 @@ This deployment method does not touch your AWS CloudFormation Stack. Instead, i serverless deploy function --function myFunction ``` +**Note:** You can always enforce a deployment using the `--force` option. + ### How It Works * The Framework packages up the targeted AWS Lambda Function into a zip file. +* The Framework fetches the hash of the already uploaded function .zip file and compares it to the local .zip file hash. +* The Framework terminates if both hashes are the same. * That zip file is uploaded to your S3 bucket using the same name as the previous function, which the CloudFormation stack is pointing to. ### Tips diff --git a/docs/providers/aws/guide/functions.md b/docs/providers/aws/guide/functions.md index de67ec3fc..afd69c320 100644 --- a/docs/providers/aws/guide/functions.md +++ b/docs/providers/aws/guide/functions.md @@ -330,7 +330,7 @@ functions: The `onError` config currently only supports SNS topic arns due to a race condition when using SQS queue arns and updating the IAM role. -We're working on a fix so that SQS queue arns are be supported in the future. +We're working on a fix so that SQS queue arns will be supported in the future. ## KMS Keys diff --git a/docs/providers/aws/guide/packaging.md b/docs/providers/aws/guide/packaging.md index fa9878c20..cbc2a51c6 100644 --- a/docs/providers/aws/guide/packaging.md +++ b/docs/providers/aws/guide/packaging.md @@ -136,3 +136,10 @@ functions: Serverless will auto-detect and exclude development dependencies based on the runtime your service is using. This ensures that only the production relevant packages and modules are included in your zip file. Doing this drastically reduces the overall size of the deployment package which will be uploaded to the cloud provider. + +You can opt-out of automatic dev dependency exclusion by setting the `excludeDevDependencies` package config to `false`: + +```yml +package: + excludeDevDependencies: false +``` diff --git a/docs/providers/aws/guide/plugins.md b/docs/providers/aws/guide/plugins.md index ce15147ae..cca69597f 100644 --- a/docs/providers/aws/guide/plugins.md +++ b/docs/providers/aws/guide/plugins.md @@ -316,6 +316,8 @@ class MyPlugin { module.exports = MyPlugin; ``` +**Note:** [Variable references](./variables.md#reference-properties-in-serverlessyml) in the `serverless` instance are not resolved before a Plugin's constructor is called, so if you need these, make sure to wait to access those from your [hooks](#hooks). + ### Command Naming Command names need to be unique. If we load two commands and both want to specify the same command (e.g. we have an integrated command `deploy` and an external command also wants to use `deploy`) the Serverless CLI will print an error and exit. If you want to have your own `deploy` command you need to name it something different like `myCompanyDeploy` so they don't clash with existing plugins. diff --git a/docs/providers/aws/guide/variables.md b/docs/providers/aws/guide/variables.md index 9a406dd80..b0e070abd 100644 --- a/docs/providers/aws/guide/variables.md +++ b/docs/providers/aws/guide/variables.md @@ -150,25 +150,43 @@ functions: In the above example, you're referencing the entire `myCustomFile.yml` file in the `custom` property. You need to pass the path relative to your service directory. You can also request specific properties in that file as shown in the `schedule` property. It's completely recursive and you can go as deep as you want. ## Reference Variables in Javascript Files -To add dynamic data into your variables, reference javascript files by putting `${file(./myFile.js):someModule}` syntax in your `serverless.yml`. Here's an example: + +You can reference JavaScript files to add dynamic data into your variables. + +References can be either named or unnamed exports. To use the exported `someModule` in `myFile.js` you'd use the following code `${file(./myFile.js):someModule}`. For an unnamed export you'd write `${file(./myFile.js)}`. + +Here are other examples: ```js -// myCustomFile.js -module.exports.hello = () => { +// scheduleConfig.js +module.exports.rate = () => { // Code that generates dynamic data return 'rate (10 minutes)'; } ``` +```js +// config.js +module.exports = () => { + return { + property1: 'some value', + property2: 'some other value' + } +} +``` + ```yml # serverless.yml service: new-service provider: aws + +custom: ${file(./config.js)} + functions: hello: handler: handler.hello events: - - schedule: ${file(./myCustomFile.js):hello} # Reference a specific module + - schedule: ${file(./scheduleConfig.js):rate} # Reference a specific module ``` You can also return an object and reference a specific property. Just make sure you are returning a valid object and referencing a valid property: diff --git a/docs/providers/azure/guide/packaging.md b/docs/providers/azure/guide/packaging.md index 040d03272..e6ffd6b87 100644 --- a/docs/providers/azure/guide/packaging.md +++ b/docs/providers/azure/guide/packaging.md @@ -157,3 +157,10 @@ functions: Serverless will auto-detect and exclude development dependencies based on the runtime your service is using. This ensures that only the production relevant packages and modules are included in your zip file. Doing this drastically reduces the overall size of the deployment package which will be uploaded to the cloud provider. + +You can opt-out of automatic dev dependency exclusion by setting the `excludeDevDependencies` package config to `false`: + +```yml +package: + excludeDevDependencies: false +``` diff --git a/docs/providers/azure/guide/plugins.md b/docs/providers/azure/guide/plugins.md index 3a7003034..b80c6df00 100644 --- a/docs/providers/azure/guide/plugins.md +++ b/docs/providers/azure/guide/plugins.md @@ -347,6 +347,8 @@ class MyPlugin { module.exports = MyPlugin; ``` +**Note:** [Variable references](./variables.md#reference-properties-in-serverlessyml) in the `serverless` instance are not resolved before a Plugin's constructor is called, so if you need these, make sure to wait to access those from your [hooks](#hooks). + ### Command Naming Command names need to be unique. If we load two commands and both want to specify diff --git a/docs/providers/azure/guide/variables.md b/docs/providers/azure/guide/variables.md index e14f867dc..dae754aac 100644 --- a/docs/providers/azure/guide/variables.md +++ b/docs/providers/azure/guide/variables.md @@ -56,27 +56,40 @@ way, you can easily change the schedule for all functions whenever you like. ## Reference Variables in JavaScript Files -To add dynamic data into your variables, reference JavaScript files by putting -`${file(./myFile.js):someModule}` syntax in your `serverless.yml`. Here's an -example: +You can reference JavaScript files to add dynamic data into your variables. + +References can be either named or unnamed exports. To use the exported `someModule` in `myFile.js` you'd use the following code `${file(./myFile.js):someModule}`. For an unnamed export you'd write `${file(./myFile.js)}`. ```js -// myCustomFile.js -module.exports.hello = () => { +// scheduleConfig.js +module.exports.cron = () => { // Code that generates dynamic data return 'cron(0 * * * *)'; } ``` +```js +// config.js +module.exports = () => { + return { + property1: 'some value', + property2: 'some other value' + } +} +``` + ```yml # serverless.yml service: new-service provider: azure + +custom: ${file(./config.js)} + functions: hello: handler: handler.hello events: - - timer: ${file(./myCustomFile.js):hello} # Reference a specific module + - timer: ${file(./scheduleConfig.js):cron} # Reference a specific module ``` You can also return an object and reference a specific property. Just make sure diff --git a/docs/providers/google/guide/packaging.md b/docs/providers/google/guide/packaging.md index 5f3ab133f..5d0e8d424 100644 --- a/docs/providers/google/guide/packaging.md +++ b/docs/providers/google/guide/packaging.md @@ -129,3 +129,10 @@ functions: Serverless will auto-detect and exclude development dependencies based on the runtime your service is using. This ensures that only the production relevant packages and modules are included in your zip file. Doing this drastically reduces the overall size of the deployment package which will be uploaded to the cloud provider. + +You can opt-out of automatic dev dependency exclusion by setting the `excludeDevDependencies` package config to `false`: + +```yml +package: + excludeDevDependencies: false +``` diff --git a/docs/providers/google/guide/plugins.md b/docs/providers/google/guide/plugins.md index 19e71b4d4..aaf032b12 100644 --- a/docs/providers/google/guide/plugins.md +++ b/docs/providers/google/guide/plugins.md @@ -315,6 +315,8 @@ class MyPlugin { module.exports = MyPlugin; ``` +**Note:** [Variable references](./variables.md#reference-properties-in-serverlessyml) in the `serverless` instance are not resolved before a Plugin's constructor is called, so if you need these, make sure to wait to access those from your [hooks](#hooks). + ### Command Naming Command names need to be unique. If we load two commands and both want to specify the same command (e.g. we have an integrated command `deploy` and an external command also wants to use `deploy`) the Serverless CLI will print an error and exit. If you want to have your own `deploy` command you need to name it something different like `myCompanyDeploy` so they don't clash with existing plugins. diff --git a/docs/providers/google/guide/variables.md b/docs/providers/google/guide/variables.md index 4aed418da..95d51d105 100644 --- a/docs/providers/google/guide/variables.md +++ b/docs/providers/google/guide/variables.md @@ -52,29 +52,43 @@ In the above example you're setting a global event resource for all functions by ## Reference Variables in JavaScript Files -To add dynamic data into your variables, reference javascript files by putting `${file(./myFile.js):someModule}` syntax in your `serverless.yml`. Here's an example: +You can reference JavaScript files to add dynamic data into your variables. + +References can be either named or unnamed exports. To use the exported `someModule` in `myFile.js` you'd use the following code `${file(./myFile.js):someModule}`. For an unnamed export you'd write `${file(./myFile.js)}`. ```javascript -// myCustomFile.js -module.exports.resource = () => { +// resources.js +module.exports.topic = () => { // Code that generates dynamic data return 'projects/*/topics/my-topic'; } ``` +```js +// config.js +module.exports = () => { + return { + property1: 'some value', + property2: 'some other value' + } +} +``` + ```yml # serverless.yml service: new-service provider: google +custom: ${file(./config.js)} + functions: first: handler: pubSub events: - event: eventType: providers/cloud.pubsub/eventTypes/topics.publish - resource: ${file(./myCustomFile.js):resource} # Reference a specific module + resource: ${file(./resources.js):topic} # Reference a specific module ``` You can also return an object and reference a specific property. Just make sure you are returning a valid object and referencing a valid property: diff --git a/docs/providers/openwhisk/events/schedule.md b/docs/providers/openwhisk/events/schedule.md index 733bfe888..52e9ca0b9 100644 --- a/docs/providers/openwhisk/events/schedule.md +++ b/docs/providers/openwhisk/events/schedule.md @@ -32,7 +32,7 @@ functions: crawl: handler: crawl events: - - schedule: cron(* * * * * *) // run every minute + - schedule: cron(* * * * *) // run every minute ``` This automatically generates a new trigger (``${service}_crawl_schedule_trigger`) diff --git a/docs/providers/openwhisk/guide/packaging.md b/docs/providers/openwhisk/guide/packaging.md index 63e9bf504..0ad78da8a 100644 --- a/docs/providers/openwhisk/guide/packaging.md +++ b/docs/providers/openwhisk/guide/packaging.md @@ -118,8 +118,39 @@ functions: - some-file.js ``` +### Exclude functions from packaging + +Sometimes you might want to exclude functions from the packaging process. The `disable` config parameter which can be defined in the `package` config on the function level enables you a way to mark a function for exclusion. + +```yml +service: my-service + +package: + individually: true + exclude: + - '**/*' + +functions: + hello: + handler: handler.hello + package: + include: + - handler.js + world: + handler: handler.hello + package: + disable: true +``` + ### Development dependencies Serverless will auto-detect and exclude development dependencies based on the runtime your service is using. This ensures that only the production relevant packages and modules are included in your zip file. Doing this drastically reduces the overall size of the deployment package which will be uploaded to the cloud provider. + +You can opt-out of automatic dev dependency exclusion by setting the `excludeDevDependencies` package config to `false`: + +```yml +package: + excludeDevDependencies: false +``` diff --git a/docs/providers/openwhisk/guide/plugins.md b/docs/providers/openwhisk/guide/plugins.md index b5aa5427f..f233ccbe9 100644 --- a/docs/providers/openwhisk/guide/plugins.md +++ b/docs/providers/openwhisk/guide/plugins.md @@ -316,6 +316,8 @@ class MyPlugin { module.exports = MyPlugin; ``` +**Note:** [Variable references](./variables.md#reference-properties-in-serverlessyml) in the `serverless` instance are not resolved before a Plugin's constructor is called, so if you need these, make sure to wait to access those from your [hooks](#hooks). + ### Command Naming Command names need to be unique. If we load two commands and both want to specify the same command (e.g. we have an integrated command `deploy` and an external command also wants to use `deploy`) the Serverless CLI will print an error and exit. If you want to have your own `deploy` command you need to name it something different like `myCompanyDeploy` so they don't clash with existing plugins. diff --git a/docs/providers/openwhisk/guide/variables.md b/docs/providers/openwhisk/guide/variables.md index bcc711cd7..eb7d60b97 100644 --- a/docs/providers/openwhisk/guide/variables.md +++ b/docs/providers/openwhisk/guide/variables.md @@ -106,25 +106,41 @@ functions: In the above example, you're referencing the entire `myCustomFile.yml` file in the `custom` property. You need to pass the path relative to your service directory. You can also request specific properties in that file as shown in the `schedule` property. It's completely recursive and you can go as deep as you want. ## Reference Variables in Javascript Files -To add dynamic data into your variables, reference javascript files by putting `${file(./myFile.js):someModule}` syntax in your `serverless.yml`. Here's an example: + +You can reference JavaScript files to add dynamic data into your variables. + +References can be either named or unnamed exports. To use the exported `someModule` in `myFile.js` you'd use the following code `${file(./myFile.js):someModule}`. For an unnamed export you'd write `${file(./myFile.js)}`. ```js -// myCustomFile.js -module.exports.hello = () => { +// scheduleConfig.js +module.exports.cron = () => { // Code that generates dynamic data return 'cron(0 * * * *)'; } ``` +```js +// config.js +module.exports = () => { + return { + property1: 'some value', + property2: 'some other value' + } +} +``` + ```yml # serverless.yml service: new-service provider: openwhisk + +custom: ${file(./config.js)} + functions: hello: handler: handler.hello events: - - schedule: ${file(./myCustomFile.js):hello} # Reference a specific module + - schedule: ${file(./scheduleConfig.js):cron} # Reference a specific module ``` You can also return an object and reference a specific property. Just make sure you are returning a valid object and referencing a valid property: diff --git a/lib/classes/Service.js b/lib/classes/Service.js index 8bb225bc8..9a5636e60 100644 --- a/lib/classes/Service.js +++ b/lib/classes/Service.js @@ -16,7 +16,7 @@ class Service { this.provider = { stage: 'dev', region: 'us-east-1', - variableSyntax: '\\${([ :a-zA-Z0-9._,\\-\\/\\(\\)]+?)}', + variableSyntax: '\\${([ ~:a-zA-Z0-9._,\\-\\/\\(\\)]+?)}', }; this.custom = {}; this.plugins = []; @@ -125,6 +125,7 @@ class Service { that.package.artifact = serverlessFile.package.artifact; that.package.exclude = serverlessFile.package.exclude; that.package.include = serverlessFile.package.include; + that.package.excludeDevDependencies = serverlessFile.package.excludeDevDependencies; } return this; diff --git a/lib/classes/Service.test.js b/lib/classes/Service.test.js index a03d7dc88..4cca7dfa9 100644 --- a/lib/classes/Service.test.js +++ b/lib/classes/Service.test.js @@ -31,7 +31,7 @@ describe('Service', () => { expect(serviceInstance.provider).to.deep.equal({ stage: 'dev', region: 'us-east-1', - variableSyntax: '\\${([ :a-zA-Z0-9._,\\-\\/\\(\\)]+?)}', + variableSyntax: '\\${([ ~:a-zA-Z0-9._,\\-\\/\\(\\)]+?)}', }); expect(serviceInstance.custom).to.deep.equal({}); expect(serviceInstance.plugins).to.deep.equal([]); @@ -80,6 +80,7 @@ describe('Service', () => { expect(serviceInstance.package.include.length).to.equal(1); expect(serviceInstance.package.include[0]).to.equal('include-me'); expect(serviceInstance.package.artifact).to.equal('some/path/foo.zip'); + expect(serviceInstance.package.excludeDevDependencies).to.equal(undefined); }); it('should support string based provider config', () => { @@ -147,6 +148,7 @@ describe('Service', () => { exclude: ['exclude-me'], include: ['include-me'], artifact: 'some/path/foo.zip', + excludeDevDependencies: false, }, }; @@ -172,6 +174,7 @@ describe('Service', () => { expect(serviceInstance.package.include.length).to.equal(1); expect(serviceInstance.package.include[0]).to.equal('include-me'); expect(serviceInstance.package.artifact).to.equal('some/path/foo.zip'); + expect(serviceInstance.package.excludeDevDependencies).to.equal(false); }); }); @@ -225,6 +228,7 @@ describe('Service', () => { expect(serviceInstance.package.include.length).to.equal(1); expect(serviceInstance.package.include[0]).to.equal('include-me'); expect(serviceInstance.package.artifact).to.equal('some/path/foo.zip'); + expect(serviceInstance.package.excludeDevDependencies).to.equal(undefined); }); }); @@ -278,6 +282,7 @@ describe('Service', () => { expect(serviceInstance.package.include.length).to.equal(1); expect(serviceInstance.package.include[0]).to.equal('include-me'); expect(serviceInstance.package.artifact).to.equal('some/path/foo.zip'); + expect(serviceInstance.package.excludeDevDependencies).to.equal(undefined); }); }); diff --git a/lib/classes/Utils.js b/lib/classes/Utils.js index 5a81955cc..d2854f347 100644 --- a/lib/classes/Utils.js +++ b/lib/classes/Utils.js @@ -249,7 +249,7 @@ class Utils { } let hasCustomVariableSyntaxDefined = false; - const defaultVariableSyntax = '\\${([ :a-zA-Z0-9._,\\-\\/\\(\\)]+?)}'; + const defaultVariableSyntax = '\\${([ ~:a-zA-Z0-9._,\\-\\/\\(\\)]+?)}'; // check if the variableSyntax in the provider section is defined if (provider && provider.variableSyntax diff --git a/lib/classes/Variables.js b/lib/classes/Variables.js index 6b575609b..fe0c9444d 100644 --- a/lib/classes/Variables.js +++ b/lib/classes/Variables.js @@ -5,6 +5,7 @@ const path = require('path'); const replaceall = require('replaceall'); const logWarning = require('./Error').logWarning; const BbPromise = require('bluebird'); +const os = require('os'); class Variables { @@ -13,7 +14,7 @@ class Variables { this.service = this.serverless.service; this.overwriteSyntax = RegExp(/,/g); - this.fileRefSyntax = RegExp(/^file\(([a-zA-Z0-9._\-/]+?)\)/g); + this.fileRefSyntax = RegExp(/^file\((~?[a-zA-Z0-9._\-/]+?)\)/g); this.envRefSyntax = RegExp(/^env:/g); this.optRefSyntax = RegExp(/^opt:/g); this.selfRefSyntax = RegExp(/^self:/g); @@ -215,12 +216,14 @@ class Variables { getValueFromFile(variableString) { const matchedFileRefString = variableString.match(this.fileRefSyntax)[0]; const referencedFileRelativePath = matchedFileRefString - .replace(this.fileRefSyntax, (match, varName) => varName.trim()); - const referencedFileFullPath = path.join(this.serverless.config.servicePath, - referencedFileRelativePath); + .replace(this.fileRefSyntax, (match, varName) => varName.trim()) + .replace('~', os.homedir()); + + const referencedFileFullPath = (path.isAbsolute(referencedFileRelativePath) ? + referencedFileRelativePath : + path.join(this.serverless.config.servicePath, referencedFileRelativePath)); let fileExtension = referencedFileRelativePath.split('.'); fileExtension = fileExtension[fileExtension.length - 1]; - // Validate file exists if (!this.serverless.utils.fileExistsSync(referencedFileFullPath)) { return BbPromise.resolve(undefined); @@ -231,9 +234,25 @@ class Variables { // Process JS files if (fileExtension === 'js') { const jsFile = require(referencedFileFullPath); // eslint-disable-line global-require - let jsModule = variableString.split(':')[1]; - jsModule = jsModule.split('.')[0]; - valueToPopulate = jsFile[jsModule](); + const variableArray = variableString.split(':'); + let returnValueFunction; + if (variableArray[1]) { + let jsModule = variableArray[1]; + jsModule = jsModule.split('.')[0]; + returnValueFunction = jsFile[jsModule]; + } else { + returnValueFunction = jsFile; + } + + if (typeof returnValueFunction !== 'function') { + throw new this.serverless.classes + .Error([ + 'Invalid variable syntax when referencing', + ` file "${referencedFileRelativePath}".`, + ' Check if your javascript is exporting a function that returns a value.', + ].join('')); + } + valueToPopulate = returnValueFunction(); return BbPromise.resolve(valueToPopulate).then(valueToPopulateResolved => { let deepProperties = variableString.replace(matchedFileRefString, ''); @@ -274,7 +293,6 @@ class Variables { return this.getDeepValue(deepProperties, valueToPopulate); } } - return BbPromise.resolve(valueToPopulate); } diff --git a/lib/classes/Variables.test.js b/lib/classes/Variables.test.js index e06bea7ab..7792006af 100644 --- a/lib/classes/Variables.test.js +++ b/lib/classes/Variables.test.js @@ -12,6 +12,7 @@ const testUtils = require('../../tests/utils'); const slsError = require('./Error'); const AwsProvider = require('../plugins/aws/provider/awsProvider'); const BbPromise = require('bluebird'); +const os = require('os'); describe('Variables', () => { describe('#constructor()', () => { @@ -535,6 +536,33 @@ describe('Variables', () => { }); describe('#getValueFromFile()', () => { + it('should work for absolute paths with ~ ', () => { + const serverless = new Serverless(); + const expectedFileName = `${os.homedir}/somedir/config.yml`; + const configYml = { + test: 1, + test2: 'test2', + testObj: { + sub: 2, + prob: 'prob', + }, + }; + const fileExistsStub = sinon + .stub(serverless.utils, 'fileExistsSync').returns(true); + + const readFileSyncStub = sinon + .stub(serverless.utils, 'readFileSync').returns(configYml); + + return serverless.variables.getValueFromFile('file(~/somedir/config.yml)') + .then(valueToPopulate => { + expect(fileExistsStub.calledWithMatch(expectedFileName)); + expect(readFileSyncStub.calledWithMatch(expectedFileName)); + expect(valueToPopulate).to.deep.equal(configYml); + readFileSyncStub.restore(); + fileExistsStub.restore(); + }); + }); + it('should populate an entire variable file', () => { const serverless = new Serverless(); const SUtils = new Utils(); @@ -639,6 +667,36 @@ describe('Variables', () => { }); }); + it('should populate an entire variable exported by a javascript file', () => { + const serverless = new Serverless(); + const SUtils = new Utils(); + const tmpDirPath = testUtils.getTmpDirPath(); + const jsData = 'module.exports=function(){return { hello: "hello world" };};'; + + SUtils.writeFileSync(path.join(tmpDirPath, 'hello.js'), jsData); + + serverless.config.update({ servicePath: tmpDirPath }); + + return serverless.variables.getValueFromFile('file(./hello.js)') + .then(valueToPopulate => { + expect(valueToPopulate.hello).to.equal('hello world'); + }); + }); + + it('should thow if property exported by a javascript file is not a function', () => { + const serverless = new Serverless(); + const SUtils = new Utils(); + const tmpDirPath = testUtils.getTmpDirPath(); + const jsData = 'module.exports={ hello: "hello world" };'; + + SUtils.writeFileSync(path.join(tmpDirPath, 'hello.js'), jsData); + + serverless.config.update({ servicePath: tmpDirPath }); + + expect(() => serverless.variables + .getValueFromFile('file(./hello.js)')).to.throw(Error); + }); + it('should populate deep object from a javascript file', () => { const serverless = new Serverless(); const SUtils = new Utils(); diff --git a/lib/plugins/aws/deploy/index.js b/lib/plugins/aws/deploy/index.js index ba4a95482..bd54900ae 100644 --- a/lib/plugins/aws/deploy/index.js +++ b/lib/plugins/aws/deploy/index.js @@ -10,9 +10,10 @@ const BbPromise = require('bluebird'); const extendedValidate = require('./lib/extendedValidate'); +const setBucketName = require('../lib/setBucketName'); +const checkForChanges = require('./lib/checkForChanges'); const monitorStack = require('../lib/monitorStack'); const createStack = require('./lib/createStack'); -const setBucketName = require('../lib/setBucketName'); const cleanupS3Bucket = require('./lib/cleanupS3Bucket'); const uploadArtifacts = require('./lib/uploadArtifacts'); const validateTemplate = require('./lib/validateTemplate'); @@ -34,6 +35,7 @@ class AwsDeploy { extendedValidate, createStack, setBucketName, + checkForChanges, cleanupS3Bucket, uploadArtifacts, validateTemplate, @@ -51,6 +53,7 @@ class AwsDeploy { deploy: { lifecycleEvents: [ 'createStack', + 'checkForChanges', 'uploadArtifacts', 'validateTemplate', 'updateStack', @@ -94,20 +97,38 @@ class AwsDeploy { 'aws:deploy:deploy:createStack': () => BbPromise.bind(this) .then(this.createStack), - 'aws:deploy:deploy:uploadArtifacts': () => BbPromise.bind(this) + 'aws:deploy:deploy:checkForChanges': () => BbPromise.bind(this) .then(this.setBucketName) - .then(this.uploadArtifacts), + .then(this.checkForChanges), + + 'aws:deploy:deploy:uploadArtifacts': () => BbPromise.bind(this) + .then(() => { + if (this.serverless.service.provider.shouldNotDeploy) { + return BbPromise.resolve(); + } + return BbPromise.bind(this).then(this.uploadArtifacts); + }), 'aws:deploy:deploy:validateTemplate': () => BbPromise.bind(this) - .then(this.validateTemplate), + .then(() => { + if (this.serverless.service.provider.shouldNotDeploy) { + return BbPromise.resolve(); + } + return BbPromise.bind(this).then(this.validateTemplate); + }), 'aws:deploy:deploy:updateStack': () => BbPromise.bind(this) - .then(this.updateStack), + .then(() => { + if (this.serverless.service.provider.shouldNotDeploy) { + return BbPromise.resolve(); + } + return BbPromise.bind(this).then(this.updateStack); + }), // Deploy finalize inner lifecycle 'aws:deploy:finalize:cleanup': () => BbPromise.bind(this) .then(() => { - if (this.options.noDeploy) { + if (this.options.noDeploy || this.serverless.service.provider.shouldNotDeploy) { return BbPromise.resolve(); } return this.cleanupS3Bucket(); diff --git a/lib/plugins/aws/deploy/index.test.js b/lib/plugins/aws/deploy/index.test.js index 610ffb6d8..31ac94eb7 100644 --- a/lib/plugins/aws/deploy/index.test.js +++ b/lib/plugins/aws/deploy/index.test.js @@ -84,9 +84,7 @@ describe('AwsDeploy', () => { let spawnStub; let createStackStub; let setBucketNameStub; - let uploadArtifactsStub; - let validateTemplateStub; - let updateStackStub; + let checkForChangesStub; beforeEach(() => { spawnStub = sinon @@ -95,21 +93,15 @@ describe('AwsDeploy', () => { .stub(awsDeploy, 'createStack').resolves(); setBucketNameStub = sinon .stub(awsDeploy, 'setBucketName').resolves(); - uploadArtifactsStub = sinon - .stub(awsDeploy, 'uploadArtifacts').resolves(); - validateTemplateStub = sinon - .stub(awsDeploy, 'validateTemplate').resolves(); - updateStackStub = sinon - .stub(awsDeploy, 'updateStack').resolves(); + checkForChangesStub = sinon + .stub(awsDeploy, 'checkForChanges').resolves(); }); afterEach(() => { serverless.pluginManager.spawn.restore(); awsDeploy.createStack.restore(); awsDeploy.setBucketName.restore(); - awsDeploy.uploadArtifacts.restore(); - awsDeploy.validateTemplate.restore(); - awsDeploy.updateStack.restore(); + awsDeploy.checkForChanges.restore(); }); describe('"before:deploy:deploy" hook', () => { @@ -193,24 +185,96 @@ describe('AwsDeploy', () => { }) ); - it('should run "aws:deploy:deploy:uploadArtifacts" hook', () => awsDeploy - .hooks['aws:deploy:deploy:uploadArtifacts']().then(() => { + it('should run "aws:deploy:deploy:checkForChanges" hook', () => awsDeploy + .hooks['aws:deploy:deploy:checkForChanges']().then(() => { expect(setBucketNameStub.calledOnce).to.equal(true); - expect(uploadArtifactsStub.calledAfter(setBucketNameStub)).to.equal(true); + expect(checkForChangesStub.calledAfter(setBucketNameStub)).to.equal(true); }) ); - it('should run "aws:deploy:deploy:validateTemplate" hook', () => expect(awsDeploy - .hooks['aws:deploy:deploy:validateTemplate']()).to.be.fulfilled.then(() => { - expect(validateTemplateStub).to.have.been.calledOnce; - }) - ); + describe('"aws:deploy:deploy:uploadArtifacts" hook', () => { + let uploadArtifactsStub; - it('should run "aws:deploy:deploy:updateStack" hook', () => awsDeploy - .hooks['aws:deploy:deploy:updateStack']().then(() => { - expect(updateStackStub.calledOnce).to.equal(true); - }) - ); + beforeEach(() => { + uploadArtifactsStub = sinon + .stub(awsDeploy, 'uploadArtifacts').resolves(); + }); + + afterEach(() => { + awsDeploy.uploadArtifacts.restore(); + }); + + it('should upload the artifacts if a deployment is necessary', () => expect(awsDeploy + .hooks['aws:deploy:deploy:uploadArtifacts']()).to.be.fulfilled.then(() => { + expect(uploadArtifactsStub).to.have.been.calledOnce; + }) + ); + + it('should resolve if no deployment is necessary', () => { + awsDeploy.serverless.service.provider.shouldNotDeploy = true; + + return expect(awsDeploy + .hooks['aws:deploy:deploy:uploadArtifacts']()).to.be.fulfilled.then(() => { + expect(uploadArtifactsStub).to.not.have.been.called; + }); + }); + }); + + describe('"aws:deploy:deploy:validateTemplate" hook', () => { + let validateTemplateStub; + + beforeEach(() => { + validateTemplateStub = sinon + .stub(awsDeploy, 'validateTemplate').resolves(); + }); + + afterEach(() => { + awsDeploy.validateTemplate.restore(); + }); + + it('should validate the template if a deployment is necessary', () => expect(awsDeploy + .hooks['aws:deploy:deploy:validateTemplate']()).to.be.fulfilled.then(() => { + expect(validateTemplateStub).to.have.been.calledOnce; + }) + ); + + it('should resolve if no deployment is necessary', () => { + awsDeploy.serverless.service.provider.shouldNotDeploy = true; + + return expect(awsDeploy + .hooks['aws:deploy:deploy:validateTemplate']()).to.be.fulfilled.then(() => { + expect(validateTemplateStub).to.not.have.been.called; + }); + }); + }); + + describe('"aws:deploy:deploy:updateStack" hook', () => { + let updateStackStub; + + beforeEach(() => { + updateStackStub = sinon + .stub(awsDeploy, 'updateStack').resolves(); + }); + + afterEach(() => { + awsDeploy.updateStack.restore(); + }); + + it('should update the stack if a deployment is necessary', () => expect(awsDeploy + .hooks['aws:deploy:deploy:updateStack']()).to.be.fulfilled.then(() => { + expect(updateStackStub).to.have.been.calledOnce; + }) + ); + + it('should resolve if no deployment is necessary', () => { + awsDeploy.serverless.service.provider.shouldNotDeploy = true; + + return expect(awsDeploy + .hooks['aws:deploy:deploy:updateStack']()).to.be.fulfilled.then(() => { + expect(updateStackStub).to.not.have.been.called; + }); + }); + }); describe('"aws:deploy:finalize:cleanup" hook', () => { let cleanupS3BucketStub; @@ -258,6 +322,15 @@ describe('AwsDeploy', () => { .to.equal(true); }); }); + + it('should not cleanup if a deployment was not necessary', () => { + awsDeploy.serverless.service.provider.shouldNotDeploy = true; + + return awsDeploy.hooks['aws:deploy:finalize:cleanup']().then(() => { + expect(cleanupS3BucketStub.called).to.equal(false); + expect(spawnAwsCommonCleanupTempDirStub.called).to.equal(false); + }); + }); }); }); }); diff --git a/lib/plugins/aws/deploy/lib/checkForChanges.js b/lib/plugins/aws/deploy/lib/checkForChanges.js new file mode 100644 index 000000000..f7cfb5fb4 --- /dev/null +++ b/lib/plugins/aws/deploy/lib/checkForChanges.js @@ -0,0 +1,119 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const crypto = require('crypto'); +const globby = require('globby'); +const BbPromise = require('bluebird'); +const _ = require('lodash'); +const normalizeFiles = require('../../lib/normalizeFiles'); + +module.exports = { + checkForChanges() { + this.serverless.service.provider.shouldNotDeploy = false; + + if (this.options.force) { + return BbPromise.resolve(); + } + + return BbPromise.bind(this) + .then(this.getMostRecentObjects) + .then(this.getObjectMetadata) + .then(this.checkIfDeploymentIsNecessary); + }, + + getMostRecentObjects() { + const service = this.serverless.service.service; + + const params = { + Bucket: this.bucketName, + Prefix: `serverless/${service}/${this.options.stage}`, + }; + + return this.provider.request('S3', + 'listObjectsV2', + params, + this.options.stage, + this.options.region + ).then((result) => { + if (result && result.Contents && result.Contents.length) { + const objects = result.Contents; + + const ordered = _.orderBy(objects, ['Key'], ['desc']); + + const firstKey = ordered[0].Key; + const directory = firstKey.substring(0, firstKey.lastIndexOf('/')); + + const mostRecentObjects = ordered.filter((obj) => { + const objKey = obj.Key; + const objDirectory = objKey.substring(0, objKey.lastIndexOf('/')); + + return directory === objDirectory; + }); + + return BbPromise.resolve(mostRecentObjects); + } + + return BbPromise.resolve([]); + }); + }, + + getObjectMetadata(objects) { + if (objects && objects.length) { + const headObjectObjects = objects + .map((obj) => this.provider.request('S3', + 'headObject', + { + Bucket: this.bucketName, + Key: obj.Key, + }, + this.options.stage, + this.options.region + )); + + return BbPromise.all(headObjectObjects) + .then((result) => result); + } + + return BbPromise.resolve([]); + }, + + checkIfDeploymentIsNecessary(objects) { + if (objects && objects.length) { + const remoteHashes = objects.map((object) => object.Metadata.filesha256 || ''); + + const serverlessDirPath = path.join(this.serverless.config.servicePath, '.serverless'); + + // create a hash of the CloudFormation body + const compiledCfTemplate = this.serverless.service.provider.compiledCloudFormationTemplate; + const normCfTemplate = normalizeFiles.normalizeCloudFormationTemplate(compiledCfTemplate); + const localCfHash = crypto + .createHash('sha256') + .update(JSON.stringify(normCfTemplate)) + .digest('base64'); + + // create hashes for all the zip files + const zipFiles = globby.sync(['**.zip'], { cwd: serverlessDirPath, dot: true, silent: true }); + const zipFilePaths = zipFiles.map((zipFile) => path.join(serverlessDirPath, zipFile)); + const zipFileHashes = zipFilePaths.map((zipFilePath) => { + // TODO refactor to be async (use util function to compute checksum async) + const zipFile = fs.readFileSync(zipFilePath); + return crypto.createHash('sha256').update(zipFile).digest('base64'); + }); + + const localHashes = zipFileHashes; + localHashes.push(localCfHash); + + if (_.isEqual(remoteHashes.sort(), localHashes.sort())) { + this.serverless.service.provider.shouldNotDeploy = true; + + const message = [ + 'Service files not changed. Skipping deployment...', + ].join(''); + this.serverless.cli.log(message); + } + } + + return BbPromise.resolve(); + }, +}; diff --git a/lib/plugins/aws/deploy/lib/checkForChanges.test.js b/lib/plugins/aws/deploy/lib/checkForChanges.test.js new file mode 100644 index 000000000..35e08bb7d --- /dev/null +++ b/lib/plugins/aws/deploy/lib/checkForChanges.test.js @@ -0,0 +1,491 @@ +'use strict'; + +/* eslint-disable no-unused-expressions */ + +const fs = require('fs'); +const path = require('path'); +const globby = require('globby'); +const sinon = require('sinon'); +const chai = require('chai'); +const proxyquire = require('proxyquire'); +const normalizeFiles = require('../../lib/normalizeFiles'); +const AwsProvider = require('../../provider/awsProvider'); +const AwsDeploy = require('../index'); +const Serverless = require('../../../../Serverless'); + +// Configure chai +chai.use(require('chai-as-promised')); +chai.use(require('sinon-chai')); +const expect = require('chai').expect; + +describe('checkForChanges', () => { + let serverless; + let awsDeploy; + let s3Key; + let cryptoStub; + + beforeEach(() => { + serverless = new Serverless(); + serverless.config.servicePath = 'my-service'; + serverless.setProvider('aws', new AwsProvider(serverless)); + serverless.service.service = 'my-service'; + const options = { + stage: 'dev', + region: 'us-east-1', + }; + awsDeploy = new AwsDeploy(serverless, options); + awsDeploy.bucketName = 'deployment-bucket'; + awsDeploy.serverless.service.provider.compiledCloudFormationTemplate = { + foo: 'bar', + }; + s3Key = `serverless/${serverless.service.service}/${options.stage}`; + awsDeploy.serverless.cli = { log: sinon.spy() }; + cryptoStub = { + createHash: function () { return this; }, // eslint-disable-line + update: function () { return this; }, // eslint-disable-line + digest: sinon.stub(), + }; + const checkForChanges = proxyquire('./checkForChanges.js', { + crypto: cryptoStub, + }); + Object.assign( + awsDeploy, + checkForChanges + ); + }); + + describe('#checkForChanges()', () => { + let getMostRecentObjectsStub; + let getObjectMetadataStub; + let checkIfDeploymentIsNecessaryStub; + + beforeEach(() => { + getMostRecentObjectsStub = sinon + .stub(awsDeploy, 'getMostRecentObjects').resolves(); + getObjectMetadataStub = sinon + .stub(awsDeploy, 'getObjectMetadata').resolves(); + checkIfDeploymentIsNecessaryStub = sinon + .stub(awsDeploy, 'checkIfDeploymentIsNecessary').resolves(); + }); + + afterEach(() => { + awsDeploy.getMostRecentObjects.restore(); + awsDeploy.getObjectMetadata.restore(); + awsDeploy.checkIfDeploymentIsNecessary.restore(); + }); + + it('should run promise chain in order', () => expect(awsDeploy.checkForChanges()) + .to.be.fulfilled.then(() => { + expect(getMostRecentObjectsStub).to.have.been.calledOnce; + expect(getObjectMetadataStub).to.have.been.calledAfter(getMostRecentObjectsStub); + expect(checkIfDeploymentIsNecessaryStub).to.have.been.calledAfter(getObjectMetadataStub); + + expect(awsDeploy.serverless.service.provider.shouldNotDeploy).to.equal(false); + }) + ); + + it('should resolve if the "force" option is used', () => { + awsDeploy.options.force = true; + + return expect(awsDeploy.checkForChanges()) + .to.be.fulfilled.then(() => { + expect(getMostRecentObjectsStub).to.not.have.been.called; + expect(getObjectMetadataStub).to.not.have.been.called; + expect(checkIfDeploymentIsNecessaryStub).to.not.have.been.called; + + expect(awsDeploy.serverless.service.provider.shouldNotDeploy).to.equal(false); + }); + }); + }); + + describe('#getMostRecentObjects()', () => { + let listObjectsV2Stub; + + beforeEach(() => { + listObjectsV2Stub = sinon + .stub(awsDeploy.provider, 'request'); + }); + + afterEach(() => { + awsDeploy.provider.request.restore(); + }); + + it('should resolve if no result is returned', () => { + listObjectsV2Stub.resolves(); + + return expect(awsDeploy.getMostRecentObjects()).to.be.fulfilled.then((result) => { + expect(listObjectsV2Stub).to.have.been.calledWithExactly( + 'S3', + 'listObjectsV2', + { + Bucket: awsDeploy.bucketName, + Prefix: 'serverless/my-service/dev', + }, + awsDeploy.options.stage, + awsDeploy.options.region + ); + expect(result).to.deep.equal([]); + }); + }); + + it('should resolve if result array is empty', () => { + const serviceObjects = { + Contents: [], + }; + + listObjectsV2Stub.resolves(serviceObjects); + + return expect(awsDeploy.getMostRecentObjects()).to.be.fulfilled.then((result) => { + expect(listObjectsV2Stub).to.have.been.calledWithExactly( + 'S3', + 'listObjectsV2', + { + Bucket: awsDeploy.bucketName, + Prefix: 'serverless/my-service/dev', + }, + awsDeploy.options.stage, + awsDeploy.options.region + ); + expect(result).to.deep.equal([]); + }); + }); + + it('should resolve with the most recently deployed objects', () => { + const serviceObjects = { + Contents: [ + { Key: `${s3Key}/151224711231-2016-08-18T15:43:00/artifact.zip` }, + { Key: `${s3Key}/151224711231-2016-08-18T15:43:00/cloudformation.json` }, + { Key: `${s3Key}/141264711231-2016-08-18T15:42:00/artifact.zip` }, + { Key: `${s3Key}/141264711231-2016-08-18T15:42:00/cloudformation.json` }, + ], + }; + + listObjectsV2Stub.resolves(serviceObjects); + + return expect(awsDeploy.getMostRecentObjects()).to.be.fulfilled.then((result) => { + expect(listObjectsV2Stub).to.have.been.calledWithExactly( + 'S3', + 'listObjectsV2', + { + Bucket: awsDeploy.bucketName, + Prefix: 'serverless/my-service/dev', + }, + awsDeploy.options.stage, + awsDeploy.options.region + ); + expect(result).to.deep.equal([ + { Key: `${s3Key}/151224711231-2016-08-18T15:43:00/cloudformation.json` }, + { Key: `${s3Key}/151224711231-2016-08-18T15:43:00/artifact.zip` }, + ]); + }); + }); + }); + + describe('#getObjectMetadata()', () => { + let headObjectStub; + + beforeEach(() => { + headObjectStub = sinon + .stub(awsDeploy.provider, 'request').resolves(); + }); + + afterEach(() => { + awsDeploy.provider.request.restore(); + }); + + it('should resolve if no input is provided', () => expect(awsDeploy.getObjectMetadata()) + .to.be.fulfilled.then((result) => { + expect(headObjectStub).to.not.have.been.called; + expect(result).to.deep.equal([]); + }) + ); + + it('should resolve if no objects are provided as input', () => { + const input = []; + + return expect(awsDeploy.getObjectMetadata(input)).to.be.fulfilled.then((result) => { + expect(headObjectStub).to.not.have.been.called; + expect(result).to.deep.equal([]); + }); + }); + + it('should request the object detailed information', () => { + const input = [ + { Key: `${s3Key}/151224711231-2016-08-18T15:43:00/artifact.zip` }, + { Key: `${s3Key}/151224711231-2016-08-18T15:43:00/cloudformation.json` }, + { Key: `${s3Key}/141264711231-2016-08-18T15:42:00/artifact.zip` }, + { Key: `${s3Key}/141264711231-2016-08-18T15:42:00/cloudformation.json` }, + ]; + + return expect(awsDeploy.getObjectMetadata(input)).to.be.fulfilled.then(() => { + expect(headObjectStub.callCount).to.equal(4); + expect(headObjectStub).to.have.been.calledWithExactly( + 'S3', + 'headObject', + { + Bucket: awsDeploy.bucketName, + Key: `${s3Key}/151224711231-2016-08-18T15:43:00/artifact.zip`, + }, + awsDeploy.options.stage, + awsDeploy.options.region + ); + expect(headObjectStub).to.have.been.calledWithExactly( + 'S3', + 'headObject', + { + Bucket: awsDeploy.bucketName, + Key: `${s3Key}/151224711231-2016-08-18T15:43:00/cloudformation.json`, + }, + awsDeploy.options.stage, + awsDeploy.options.region + ); + expect(headObjectStub).to.have.been.calledWithExactly( + 'S3', + 'headObject', + { + Bucket: awsDeploy.bucketName, + Key: `${s3Key}/141264711231-2016-08-18T15:42:00/artifact.zip`, + }, + awsDeploy.options.stage, + awsDeploy.options.region + ); + expect(headObjectStub).to.have.been.calledWithExactly( + 'S3', + 'headObject', + { + Bucket: awsDeploy.bucketName, + Key: `${s3Key}/141264711231-2016-08-18T15:42:00/cloudformation.json`, + }, + awsDeploy.options.stage, + awsDeploy.options.region + ); + }); + }); + }); + + describe('#checkIfDeploymentIsNecessary()', () => { + let normalizeCloudFormationTemplateStub; + let globbySyncStub; + let readFileSyncStub; + + beforeEach(() => { + normalizeCloudFormationTemplateStub = sinon + .stub(normalizeFiles, 'normalizeCloudFormationTemplate') + .returns(); + globbySyncStub = sinon + .stub(globby, 'sync'); + readFileSyncStub = sinon + .stub(fs, 'readFileSync') + .returns(); + }); + + afterEach(() => { + normalizeFiles.normalizeCloudFormationTemplate.restore(); + globby.sync.restore(); + fs.readFileSync.restore(); + }); + + it('should resolve if no input is provided', () => expect(awsDeploy + .checkIfDeploymentIsNecessary()).to.be.fulfilled.then(() => { + expect(normalizeCloudFormationTemplateStub).to.not.have.been.called; + expect(globbySyncStub).to.not.have.been.called; + expect(readFileSyncStub).to.not.have.been.called; + expect(awsDeploy.serverless.cli.log).to.not.have.been.called; + }) + ); + + it('should resolve if no objects are provided as input', () => { + const input = []; + + return expect(awsDeploy.checkIfDeploymentIsNecessary(input)) + .to.be.fulfilled.then(() => { + expect(normalizeCloudFormationTemplateStub).to.not.have.been.called; + expect(globbySyncStub).to.not.have.been.called; + expect(readFileSyncStub).to.not.have.been.called; + expect(awsDeploy.serverless.cli.log).to.not.have.been.called; + }); + }); + + it('should not set a flag if there are more remote hashes', () => { + globbySyncStub.returns(['my-service.zip']); + cryptoStub.createHash().update().digest.onCall(0).returns('local-hash-cf-template'); + cryptoStub.createHash().update().digest.onCall(1).returns('local-hash-zip-file-1'); + + const input = [ + { Metadata: { filesha256: 'remote-hash-cf-template' } }, + { Metadata: { filesha256: 'remote-hash-zip-file-1' } }, + { Metadata: { /* no filesha256 available */ } }, // will be translated to '' + ]; + + return expect(awsDeploy.checkIfDeploymentIsNecessary(input)) + .to.be.fulfilled.then(() => { + expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce; + expect(globbySyncStub).to.have.been.calledOnce; + expect(readFileSyncStub).to.have.been.calledOnce; + expect(awsDeploy.serverless.cli.log).to.not.have.been.called; + expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly( + awsDeploy.serverless.service.provider.compiledCloudFormationTemplate + ); + expect(globbySyncStub).to.have.been.calledWithExactly( + ['**.zip'], + { + cwd: path.join(awsDeploy.serverless.config.servicePath, '.serverless'), + dot: true, + silent: true, + } + ); + expect(readFileSyncStub).to.have.been.calledWithExactly( + 'my-service/.serverless/my-service.zip' + ); + expect(awsDeploy.serverless.service.provider.shouldNotDeploy).to.equal(undefined); + }); + }); + + it('should not set a flag if remote and local hashes are different', () => { + globbySyncStub.returns(['my-service.zip']); + cryptoStub.createHash().update().digest.onCall(0).returns('local-hash-cf-template'); + cryptoStub.createHash().update().digest.onCall(1).returns('local-hash-zip-file-1'); + + const input = [ + { Metadata: { filesha256: 'remote-hash-cf-template' } }, + { Metadata: { filesha256: 'remote-hash-zip-file-1' } }, + ]; + + return expect(awsDeploy.checkIfDeploymentIsNecessary(input)) + .to.be.fulfilled.then(() => { + expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce; + expect(globbySyncStub).to.have.been.calledOnce; + expect(readFileSyncStub).to.have.been.calledOnce; + expect(awsDeploy.serverless.cli.log).to.not.have.been.called; + expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly( + awsDeploy.serverless.service.provider.compiledCloudFormationTemplate + ); + expect(globbySyncStub).to.have.been.calledWithExactly( + ['**.zip'], + { + cwd: path.join(awsDeploy.serverless.config.servicePath, '.serverless'), + dot: true, + silent: true, + } + ); + expect(readFileSyncStub).to.have.been.calledWithExactly( + 'my-service/.serverless/my-service.zip' + ); + expect(awsDeploy.serverless.service.provider.shouldNotDeploy).to.equal(undefined); + }); + }); + + it('should not set a flag if remote and local hashes are the same but are duplicated', () => { + globbySyncStub.returns(['func1.zip', 'func2.zip']); + cryptoStub.createHash().update().digest.onCall(0).returns('remote-hash-cf-template'); + // happens when package.individually is used + cryptoStub.createHash().update().digest.onCall(1).returns('remote-hash-zip-file-1'); + cryptoStub.createHash().update().digest.onCall(2).returns('remote-hash-zip-file-1'); + + const input = [ + { Metadata: { filesha256: 'remote-hash-cf-template' } }, + { Metadata: { filesha256: 'remote-hash-zip-file-1' } }, + ]; + + return expect(awsDeploy.checkIfDeploymentIsNecessary(input)) + .to.be.fulfilled.then(() => { + expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce; + expect(globbySyncStub).to.have.been.calledOnce; + expect(readFileSyncStub).to.have.been.calledTwice; + expect(awsDeploy.serverless.cli.log).to.not.have.been.called; + expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly( + awsDeploy.serverless.service.provider.compiledCloudFormationTemplate + ); + expect(globbySyncStub).to.have.been.calledWithExactly( + ['**.zip'], + { + cwd: path.join(awsDeploy.serverless.config.servicePath, '.serverless'), + dot: true, + silent: true, + } + ); + expect(readFileSyncStub).to.have.been.calledWithExactly( + 'my-service/.serverless/func1.zip' + ); + expect(readFileSyncStub).to.have.been.calledWithExactly( + 'my-service/.serverless/func2.zip' + ); + expect(awsDeploy.serverless.service.provider.shouldNotDeploy).to.equal(undefined); + }); + }); + + it('should set a flag if the remote and local hashes are equal', () => { + globbySyncStub.returns(['my-service.zip']); + cryptoStub.createHash().update().digest.onCall(0).returns('hash-cf-template'); + cryptoStub.createHash().update().digest.onCall(1).returns('hash-zip-file-1'); + + const input = [ + { Metadata: { filesha256: 'hash-cf-template' } }, + { Metadata: { filesha256: 'hash-zip-file-1' } }, + ]; + + return expect(awsDeploy.checkIfDeploymentIsNecessary(input)) + .to.be.fulfilled.then(() => { + expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce; + expect(globbySyncStub).to.have.been.calledOnce; + expect(readFileSyncStub).to.have.been.calledOnce; + expect(awsDeploy.serverless.cli.log).to.have.been.calledOnce; + expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly( + awsDeploy.serverless.service.provider.compiledCloudFormationTemplate + ); + expect(globbySyncStub).to.have.been.calledWithExactly( + ['**.zip'], + { + cwd: path.join(awsDeploy.serverless.config.servicePath, '.serverless'), + dot: true, + silent: true, + } + ); + expect(readFileSyncStub).to.have.been.calledWithExactly( + 'my-service/.serverless/my-service.zip' + ); + expect(awsDeploy.serverless.service.provider.shouldNotDeploy).to.equal(true); + }); + }); + + it('should set a flag if the remote and local hashes are duplicated and equal', () => { + globbySyncStub.returns(['func1.zip', 'func2.zip']); + cryptoStub.createHash().update().digest.onCall(0).returns('hash-cf-template'); + // happens when package.individually is used + cryptoStub.createHash().update().digest.onCall(1).returns('hash-zip-file-1'); + cryptoStub.createHash().update().digest.onCall(2).returns('hash-zip-file-1'); + + const input = [ + { Metadata: { filesha256: 'hash-cf-template' } }, + { Metadata: { filesha256: 'hash-zip-file-1' } }, + { Metadata: { filesha256: 'hash-zip-file-1' } }, + ]; + + return expect(awsDeploy.checkIfDeploymentIsNecessary(input)) + .to.be.fulfilled.then(() => { + expect(normalizeCloudFormationTemplateStub).to.have.been.calledOnce; + expect(globbySyncStub).to.have.been.calledOnce; + expect(readFileSyncStub).to.have.been.calledTwice; + expect(awsDeploy.serverless.cli.log).to.have.been.calledOnce; + expect(normalizeCloudFormationTemplateStub).to.have.been.calledWithExactly( + awsDeploy.serverless.service.provider.compiledCloudFormationTemplate + ); + expect(globbySyncStub).to.have.been.calledWithExactly( + ['**.zip'], + { + cwd: path.join(awsDeploy.serverless.config.servicePath, '.serverless'), + dot: true, + silent: true, + } + ); + expect(readFileSyncStub).to.have.been.calledWithExactly( + 'my-service/.serverless/func1.zip' + ); + expect(readFileSyncStub).to.have.been.calledWithExactly( + 'my-service/.serverless/func2.zip' + ); + expect(awsDeploy.serverless.service.provider.shouldNotDeploy).to.equal(true); + }); + }); + }); +}); diff --git a/lib/plugins/aws/deploy/lib/extendedValidate.js b/lib/plugins/aws/deploy/lib/extendedValidate.js index 595e7ca6b..0c670d128 100644 --- a/lib/plugins/aws/deploy/lib/extendedValidate.js +++ b/lib/plugins/aws/deploy/lib/extendedValidate.js @@ -33,8 +33,16 @@ module.exports = { this.serverless.service.package.individually) { // artifact file validation (multiple function artifacts) this.serverless.service.getAllFunctions().forEach(functionName => { - const artifactFileName = this.provider.naming.getFunctionArtifactName(functionName); - const artifactFilePath = path.join(this.packagePath, artifactFileName); + let artifactFileName = this.provider.naming.getFunctionArtifactName(functionName); + let artifactFilePath = path.join(this.packagePath, artifactFileName); + + // check if an artifact is used in function package level + const functionObject = this.serverless.service.getFunction(functionName); + if (_.has(functionObject, ['package', 'artifact'])) { + artifactFilePath = functionObject.package.artifact; + artifactFileName = path.basename(artifactFilePath); + } + if (!this.serverless.utils.fileExistsSync(artifactFilePath)) { throw new this.serverless.classes .Error(`No ${artifactFileName} file found in the package path you provided.`); @@ -42,8 +50,14 @@ module.exports = { }); } else if (!_.isEmpty(this.serverless.service.functions)) { // artifact file validation (single service artifact) - const artifactFileName = this.provider.naming.getServiceArtifactName(); - const artifactFilePath = path.join(this.packagePath, artifactFileName); + let artifactFilePath; + let artifactFileName; + if (this.serverless.service.package.artifact) { + artifactFileName = artifactFilePath = this.serverless.service.package.artifact; + } else { + artifactFileName = this.provider.naming.getServiceArtifactName(); + artifactFilePath = path.join(this.packagePath, artifactFileName); + } if (!this.serverless.utils.fileExistsSync(artifactFilePath)) { throw new this.serverless.classes .Error(`No ${artifactFileName} file found in the package path you provided.`); diff --git a/lib/plugins/aws/deploy/lib/extendedValidate.test.js b/lib/plugins/aws/deploy/lib/extendedValidate.test.js index 5015fb12a..5e0d010b1 100644 --- a/lib/plugins/aws/deploy/lib/extendedValidate.test.js +++ b/lib/plugins/aws/deploy/lib/extendedValidate.test.js @@ -46,57 +46,106 @@ describe('extendedValidate', () => { }); describe('extendedValidate()', () => { - it('should throw error if state file does not exist', () => { - sinon.stub(awsDeploy.serverless.utils, 'fileExistsSync').returns(false); - expect(() => awsDeploy.extendedValidate()).to.throw(Error); + let fileExistsSyncStub; + let readFileSyncStub; + + beforeEach(() => { + fileExistsSyncStub = sinon + .stub(awsDeploy.serverless.utils, 'fileExistsSync'); + readFileSyncStub = sinon + .stub(awsDeploy.serverless.utils, 'readFileSync'); + awsDeploy.serverless.service.package.individually = false; + }); + + afterEach(() => { awsDeploy.serverless.utils.fileExistsSync.restore(); + awsDeploy.serverless.utils.readFileSync.restore(); + }); + + it('should throw error if state file does not exist', () => { + fileExistsSyncStub.returns(false); + + expect(() => awsDeploy.extendedValidate()).to.throw(Error); }); it('should throw error if packaged individually but functions packages do not exist', () => { - const fileExistsSyncStub = sinon.stub(awsDeploy.serverless.utils, 'fileExistsSync'); fileExistsSyncStub.onCall(0).returns(true); fileExistsSyncStub.onCall(1).returns(false); - sinon.stub(awsDeploy.serverless.utils, 'readFileSync').returns(stateFileMock); + readFileSyncStub.returns(stateFileMock); + awsDeploy.serverless.service.package.individually = true; + expect(() => awsDeploy.extendedValidate()).to.throw(Error); - awsDeploy.serverless.service.package.individually = false; - awsDeploy.serverless.utils.fileExistsSync.restore(); - awsDeploy.serverless.utils.readFileSync.restore(); }); it('should throw error if service package does not exist', () => { - const fileExistsSyncStub = sinon.stub(awsDeploy.serverless.utils, 'fileExistsSync'); fileExistsSyncStub.onCall(0).returns(true); fileExistsSyncStub.onCall(1).returns(false); - sinon.stub(awsDeploy.serverless.utils, 'readFileSync').returns(stateFileMock); + readFileSyncStub.returns(stateFileMock); + expect(() => awsDeploy.extendedValidate()).to.throw(Error); - awsDeploy.serverless.utils.fileExistsSync.restore(); - awsDeploy.serverless.utils.readFileSync.restore(); }); - it('should not throw error if service has no functions and no service package available', () => { // eslint-disable-line max-len - const functionsTmp = stateFileMock.service.functions; + it('should not throw error if service has no functions and no service package', () => { stateFileMock.service.functions = {}; - sinon.stub(awsDeploy.serverless.utils, 'fileExistsSync').returns(true); - sinon.stub(awsDeploy.serverless.utils, 'readFileSync').returns(stateFileMock); + fileExistsSyncStub.returns(true); + readFileSyncStub.returns(stateFileMock); + return awsDeploy.extendedValidate().then(() => { - stateFileMock.service.functions = functionsTmp; - awsDeploy.serverless.utils.fileExistsSync.restore(); - awsDeploy.serverless.utils.readFileSync.restore(); + expect(fileExistsSyncStub.calledOnce).to.equal(true); + expect(readFileSyncStub.calledOnce).to.equal(true); }); }); - it('should not throw error if service has no functions and no function packages available', () => { // eslint-disable-line max-len - const functionsTmp = stateFileMock.service.functions; + it('should not throw error if service has no functions and no function packages', () => { stateFileMock.service.functions = {}; awsDeploy.serverless.service.package.individually = true; - sinon.stub(awsDeploy.serverless.utils, 'fileExistsSync').returns(true); - sinon.stub(awsDeploy.serverless.utils, 'readFileSync').returns(stateFileMock); + fileExistsSyncStub.returns(true); + readFileSyncStub.returns(stateFileMock); + return awsDeploy.extendedValidate().then(() => { - awsDeploy.serverless.service.package.individually = false; - stateFileMock.service.functions = functionsTmp; - awsDeploy.serverless.utils.fileExistsSync.restore(); - awsDeploy.serverless.utils.readFileSync.restore(); + expect(fileExistsSyncStub.calledOnce).to.equal(true); + expect(readFileSyncStub.calledOnce).to.equal(true); + }); + }); + + it('should use function package level artifact when provided', () => { + stateFileMock.service.functions = { + first: { + package: { + artifact: 'artifact.zip', + }, + }, + }; + awsDeploy.serverless.service.package.individually = true; + fileExistsSyncStub.returns(true); + readFileSyncStub.returns(stateFileMock); + + return awsDeploy.extendedValidate().then(() => { + expect(fileExistsSyncStub.calledTwice).to.equal(true); + expect(readFileSyncStub.calledOnce).to.equal(true); + expect(fileExistsSyncStub).to.have.been.calledWithExactly('artifact.zip'); + }); + }); + + it('should throw error if specified package artifact does not exist', () => { + // const fileExistsSyncStub = sinon.stub(awsDeploy.serverless.utils, 'fileExistsSync'); + fileExistsSyncStub.onCall(0).returns(true); + fileExistsSyncStub.onCall(1).returns(false); + readFileSyncStub.returns(stateFileMock); + awsDeploy.serverless.service.package.artifact = 'some/file.zip'; + expect(() => awsDeploy.extendedValidate()).to.throw(Error); + delete awsDeploy.serverless.service.package.artifact; + }); + + it('should not throw error if specified package artifact exists', () => { + // const fileExistsSyncStub = sinon.stub(awsDeploy.serverless.utils, 'fileExistsSync'); + fileExistsSyncStub.onCall(0).returns(true); + fileExistsSyncStub.onCall(1).returns(true); + readFileSyncStub.returns(stateFileMock); + awsDeploy.serverless.service.package.artifact = 'some/file.zip'; + return awsDeploy.extendedValidate().then(() => { + delete awsDeploy.serverless.service.package.artifact; }); }); }); diff --git a/lib/plugins/aws/deploy/lib/uploadArtifacts.js b/lib/plugins/aws/deploy/lib/uploadArtifacts.js index 36065bca0..380fcea1e 100644 --- a/lib/plugins/aws/deploy/lib/uploadArtifacts.js +++ b/lib/plugins/aws/deploy/lib/uploadArtifacts.js @@ -3,22 +3,39 @@ /* eslint-disable no-use-before-define */ const fs = require('fs'); +const path = require('path'); +const crypto = require('crypto'); const BbPromise = require('bluebird'); const filesize = require('filesize'); -const path = require('path'); +const normalizeFiles = require('../../lib/normalizeFiles'); module.exports = { + uploadArtifacts() { + return BbPromise.bind(this) + .then(this.uploadCloudFormationFile) + .then(this.uploadFunctions); + }, + uploadCloudFormationFile() { this.serverless.cli.log('Uploading CloudFormation file to S3...'); const compiledTemplateFileName = 'compiled-cloudformation-template.json'; - const body = JSON.stringify(this.serverless.service.provider.compiledCloudFormationTemplate); + const compiledCfTemplate = this.serverless.service.provider.compiledCloudFormationTemplate; + const normCfTemplate = normalizeFiles.normalizeCloudFormationTemplate(compiledCfTemplate); + const fileHash = crypto + .createHash('sha256') + .update(JSON.stringify(normCfTemplate)) + .digest('base64'); + let params = { Bucket: this.bucketName, Key: `${this.serverless.service.package.artifactDirectoryName}/${compiledTemplateFileName}`, - Body: body, + Body: JSON.stringify(compiledCfTemplate), ContentType: 'application/json', + Metadata: { + filesha256: fileHash, + }, }; const deploymentBucketObject = this.serverless.service.provider.deploymentBucketObject; @@ -36,11 +53,18 @@ module.exports = { uploadZipFile(artifactFilePath) { const fileName = artifactFilePath.split(path.sep).pop(); + // TODO refactor to be async (use util function to compute checksum async) + const data = fs.readFileSync(artifactFilePath); + const fileHash = crypto.createHash('sha256').update(data).digest('base64'); + let params = { Bucket: this.bucketName, Key: `${this.serverless.service.package.artifactDirectoryName}/${fileName}`, Body: fs.createReadStream(artifactFilePath), ContentType: 'application/zip', + Metadata: { + filesha256: fileHash, + }, }; const deploymentBucketObject = this.serverless.service.provider.deploymentBucketObject; @@ -89,12 +113,6 @@ module.exports = { return BbPromise.resolve(); }); }, - - uploadArtifacts() { - return BbPromise.bind(this) - .then(this.uploadCloudFormationFile) - .then(this.uploadFunctions); - }, }; function setServersideEncryptionOptions(putParams, deploymentBucketOptions) { diff --git a/lib/plugins/aws/deploy/lib/uploadArtifacts.test.js b/lib/plugins/aws/deploy/lib/uploadArtifacts.test.js index 9f6d01809..059495288 100644 --- a/lib/plugins/aws/deploy/lib/uploadArtifacts.test.js +++ b/lib/plugins/aws/deploy/lib/uploadArtifacts.test.js @@ -1,17 +1,20 @@ 'use strict'; const sinon = require('sinon'); +const fs = require('fs'); const path = require('path'); const expect = require('chai').expect; +const proxyquire = require('proxyquire'); +const normalizeFiles = require('../../lib/normalizeFiles'); const AwsProvider = require('../../provider/awsProvider'); const AwsDeploy = require('../index'); const Serverless = require('../../../../Serverless'); const testUtils = require('../../../../../tests/utils'); -const fs = require('fs'); describe('uploadArtifacts', () => { let serverless; let awsDeploy; + let cryptoStub; beforeEach(() => { serverless = new Serverless(); @@ -29,19 +32,66 @@ describe('uploadArtifacts', () => { handler: 'foo', }, }; - + awsDeploy.serverless.service.provider.compiledCloudFormationTemplate = { + foo: 'bar', + }; awsDeploy.serverless.cli = new serverless.classes.CLI(); + cryptoStub = { + createHash: function () { return this; }, // eslint-disable-line + update: function () { return this; }, // eslint-disable-line + digest: sinon.stub(), + }; + const uploadArtifacts = proxyquire('./uploadArtifacts.js', { + crypto: cryptoStub, + }); + Object.assign( + awsDeploy, + uploadArtifacts + ); + }); + + describe('#uploadArtifacts()', () => { + it('should run promise chain in order', () => { + const uploadCloudFormationFileStub = sinon + .stub(awsDeploy, 'uploadCloudFormationFile').resolves(); + const uploadFunctionsStub = sinon + .stub(awsDeploy, 'uploadFunctions').resolves(); + + return awsDeploy.uploadArtifacts().then(() => { + expect(uploadCloudFormationFileStub.calledOnce) + .to.be.equal(true); + expect(uploadFunctionsStub.calledAfter(uploadCloudFormationFileStub)).to.be.equal(true); + + awsDeploy.uploadCloudFormationFile.restore(); + awsDeploy.uploadFunctions.restore(); + }); + }); }); describe('#uploadCloudFormationFile()', () => { - it('should upload the CloudFormation file to the S3 bucket', () => { - awsDeploy.serverless.service.provider.compiledCloudFormationTemplate = { key: 'value' }; + let normalizeCloudFormationTemplateStub; + let putObjectStub; - const putObjectStub = sinon - .stub(awsDeploy.provider, 'request').resolves(); + beforeEach(() => { + normalizeCloudFormationTemplateStub = sinon + .stub(normalizeFiles, 'normalizeCloudFormationTemplate') + .returns(); + putObjectStub = sinon + .stub(awsDeploy.provider, 'request') + .resolves(); + }); + + afterEach(() => { + normalizeFiles.normalizeCloudFormationTemplate.restore(); + awsDeploy.provider.request.restore(); + }); + + it('should upload the CloudFormation file to the S3 bucket', () => { + cryptoStub.createHash().update().digest.onCall(0).returns('local-hash-cf-template'); return awsDeploy.uploadCloudFormationFile().then(() => { - expect(putObjectStub.calledOnce).to.be.equal(true); + expect(normalizeCloudFormationTemplateStub.calledOnce).to.equal(true); + expect(putObjectStub.calledOnce).to.equal(true); expect(putObjectStub.calledWithExactly( 'S3', 'putObject', @@ -49,27 +99,28 @@ describe('uploadArtifacts', () => { Bucket: awsDeploy.bucketName, Key: `${awsDeploy.serverless.service.package .artifactDirectoryName}/compiled-cloudformation-template.json`, - Body: JSON.stringify(awsDeploy.serverless.service.provider - .compiledCloudFormationTemplate), + Body: JSON.stringify({ foo: 'bar' }), ContentType: 'application/json', + Metadata: { + filesha256: 'local-hash-cf-template', + }, }, awsDeploy.options.stage, awsDeploy.options.region )).to.be.equal(true); - awsDeploy.provider.request.restore(); + expect(normalizeCloudFormationTemplateStub.calledWithExactly({ foo: 'bar' })) + .to.equal(true); }); }); - it('should upload to a bucket with server side encryption bucket policy', () => { - awsDeploy.serverless.service.provider.compiledCloudFormationTemplate = { key: 'value' }; + it('should upload the CloudFormation file to a bucket with SSE bucket policy', () => { + cryptoStub.createHash().update().digest.onCall(0).returns('local-hash-cf-template'); awsDeploy.serverless.service.provider.deploymentBucketObject = { serverSideEncryption: 'AES256', }; - const putObjectStub = sinon - .stub(awsDeploy.provider, 'request').resolves(); - return awsDeploy.uploadCloudFormationFile().then(() => { + expect(normalizeCloudFormationTemplateStub.calledOnce).to.equal(true); expect(putObjectStub.calledOnce).to.be.equal(true); expect(putObjectStub.calledWithExactly( 'S3', @@ -78,36 +129,54 @@ describe('uploadArtifacts', () => { Bucket: awsDeploy.bucketName, Key: `${awsDeploy.serverless.service.package .artifactDirectoryName}/compiled-cloudformation-template.json`, - Body: JSON.stringify(awsDeploy.serverless.service.provider - .compiledCloudFormationTemplate), + Body: JSON.stringify({ foo: 'bar' }), ContentType: 'application/json', ServerSideEncryption: 'AES256', + Metadata: { + filesha256: 'local-hash-cf-template', + }, }, awsDeploy.options.stage, awsDeploy.options.region )).to.be.equal(true); - - awsDeploy.provider.request.restore(); + expect(normalizeCloudFormationTemplateStub.calledWithExactly({ foo: 'bar' })) + .to.equal(true); }); }); }); describe('#uploadZipFile()', () => { + let readFileSyncStub; + let putObjectStub; + + beforeEach(() => { + readFileSyncStub = sinon + .stub(fs, 'readFileSync') + .returns(); + putObjectStub = sinon + .stub(awsDeploy.provider, 'request') + .resolves(); + }); + + afterEach(() => { + fs.readFileSync.restore(); + awsDeploy.provider.request.restore(); + }); + it('should throw for null artifact paths', () => { - sinon.stub(awsDeploy.provider, 'request').resolves(); expect(() => awsDeploy.uploadZipFile(null)).to.throw(Error); }); it('should upload the .zip file to the S3 bucket', () => { + cryptoStub.createHash().update().digest.onCall(0).returns('local-hash-zip-file'); + const tmpDirPath = testUtils.getTmpDirPath(); const artifactFilePath = path.join(tmpDirPath, 'artifact.zip'); serverless.utils.writeFileSync(artifactFilePath, 'artifact.zip file content'); - const putObjectStub = sinon - .stub(awsDeploy.provider, 'request').resolves(); - return awsDeploy.uploadZipFile(artifactFilePath).then(() => { expect(putObjectStub.calledOnce).to.be.equal(true); + expect(readFileSyncStub.calledOnce).to.equal(true); expect(putObjectStub.calledWithExactly( 'S3', 'putObject', @@ -116,26 +185,30 @@ describe('uploadArtifacts', () => { Key: `${awsDeploy.serverless.service.package.artifactDirectoryName}/artifact.zip`, Body: sinon.match.object.and(sinon.match.has('path', artifactFilePath)), ContentType: 'application/zip', + Metadata: { + filesha256: 'local-hash-zip-file', + }, }, awsDeploy.options.stage, awsDeploy.options.region )).to.be.equal(true); - awsDeploy.provider.request.restore(); + expect(readFileSyncStub.calledWithExactly(artifactFilePath)).to.equal(true); }); }); - it('should upload to a bucket with server side encryption bucket policy', () => { + it('should upload the .zip file to a bucket with SSE bucket policy', () => { + cryptoStub.createHash().update().digest.onCall(0).returns('local-hash-zip-file'); + const tmpDirPath = testUtils.getTmpDirPath(); const artifactFilePath = path.join(tmpDirPath, 'artifact.zip'); serverless.utils.writeFileSync(artifactFilePath, 'artifact.zip file content'); awsDeploy.serverless.service.provider.deploymentBucketObject = { serverSideEncryption: 'AES256', }; - const putObjectStub = sinon - .stub(awsDeploy.provider, 'request').resolves(); return awsDeploy.uploadZipFile(artifactFilePath).then(() => { expect(putObjectStub.calledOnce).to.be.equal(true); + expect(readFileSyncStub.calledOnce).to.equal(true); expect(putObjectStub.calledWithExactly( 'S3', 'putObject', @@ -145,11 +218,14 @@ describe('uploadArtifacts', () => { Body: sinon.match.object.and(sinon.match.has('path', artifactFilePath)), ContentType: 'application/zip', ServerSideEncryption: 'AES256', + Metadata: { + filesha256: 'local-hash-zip-file', + }, }, awsDeploy.options.stage, awsDeploy.options.region )).to.be.equal(true); - awsDeploy.provider.request.restore(); + expect(readFileSyncStub.calledWithExactly(artifactFilePath)).to.equal(true); }); }); }); @@ -246,22 +322,4 @@ describe('uploadArtifacts', () => { }); }); }); - - describe('#uploadArtifacts()', () => { - it('should run promise chain in order', () => { - const uploadCloudFormationFileStub = sinon - .stub(awsDeploy, 'uploadCloudFormationFile').resolves(); - const uploadFunctionsStub = sinon - .stub(awsDeploy, 'uploadFunctions').resolves(); - - return awsDeploy.uploadArtifacts().then(() => { - expect(uploadCloudFormationFileStub.calledOnce) - .to.be.equal(true); - expect(uploadFunctionsStub.calledAfter(uploadCloudFormationFileStub)).to.be.equal(true); - - awsDeploy.uploadCloudFormationFile.restore(); - awsDeploy.uploadFunctions.restore(); - }); - }); - }); }); diff --git a/lib/plugins/aws/deployFunction/index.js b/lib/plugins/aws/deployFunction/index.js index b7fee0453..0d7b0da94 100644 --- a/lib/plugins/aws/deployFunction/index.js +++ b/lib/plugins/aws/deployFunction/index.js @@ -1,6 +1,8 @@ 'use strict'; const BbPromise = require('bluebird'); +const _ = require('lodash'); +const crypto = require('crypto'); const path = require('path'); const fs = require('fs'); const validate = require('../lib/validate'); @@ -15,12 +17,14 @@ class AwsDeployFunction { path.join(this.serverless.config.servicePath || '.', '.serverless'); this.provider = this.serverless.getProvider('aws'); + // used to store data received via AWS SDK + this.serverless.service.provider.remoteFunctionData = null; + Object.assign(this, validate); this.hooks = { 'deploy:function:initialize': () => BbPromise.bind(this) .then(this.validate) - .then(this.logStatus) .then(this.checkIfFunctionExists), 'deploy:function:packageFunction': () => this.serverless.pluginManager @@ -32,11 +36,6 @@ class AwsDeployFunction { }; } - logStatus() { - this.serverless.cli.log(`Deploying function: ${this.options.function}...`); - return BbPromise.resolve(); - } - checkIfFunctionExists() { // check if the function exists in the service this.options.functionObj = this.serverless.service.getFunction(this.options.function); @@ -46,43 +45,59 @@ class AwsDeployFunction { FunctionName: this.options.functionObj.name, }; - this.provider.request( + return this.provider.request( 'Lambda', 'getFunction', params, this.options.stage, this.options.region - ).catch(() => { + ) + .then((result) => { + this.serverless.service.provider.remoteFunctionData = result; + return result; + }) + .catch(() => { const errorMessage = [ `The function "${this.options.function}" you want to update is not yet deployed.`, ' Please run "serverless deploy" to deploy your service.', ' After that you can redeploy your services functions with the', ' "serverless deploy function" command.', ].join(''); - throw new this.serverless.classes - .Error(errorMessage); + throw new this.serverless.classes.Error(errorMessage); }); - - return BbPromise.resolve(); } deployFunction() { const artifactFileName = this.provider.naming .getFunctionArtifactName(this.options.function); - const artifactFilePath = path.join(this.packagePath, artifactFileName); + let artifactFilePath = this.serverless.service.package.artifact || + path.join(this.packagePath, artifactFileName); + + // check if an artifact is used in function package level + const functionObject = this.serverless.service.getFunction(this.options.function); + if (_.has(functionObject, ['package', 'artifact'])) { + artifactFilePath = functionObject.package.artifact; + } + const data = fs.readFileSync(artifactFilePath); + const remoteHash = this.serverless.service.provider.remoteFunctionData.Configuration.CodeSha256; + const localHash = crypto.createHash('sha256').update(data).digest('base64'); + + if (remoteHash === localHash && !this.options.force) { + this.serverless.cli.log('Code not changed. Skipping function deployment.'); + return BbPromise.resolve(); + } + const params = { FunctionName: this.options.functionObj.name, ZipFile: data, }; - // Get function stats const stats = fs.statSync(artifactFilePath); this.serverless.cli.log( `Uploading function: ${this.options.function} (${filesize(stats.size)})...` ); - // Perform upload return this.provider.request( 'Lambda', 'updateFunctionCode', diff --git a/lib/plugins/aws/deployFunction/index.test.js b/lib/plugins/aws/deployFunction/index.test.js index 9254328ae..ca90d43d8 100644 --- a/lib/plugins/aws/deployFunction/index.test.js +++ b/lib/plugins/aws/deployFunction/index.test.js @@ -4,14 +4,16 @@ const expect = require('chai').expect; const sinon = require('sinon'); const path = require('path'); const fs = require('fs'); +const proxyquire = require('proxyquire'); const AwsProvider = require('../provider/awsProvider'); -const AwsDeployFunction = require('./index'); const Serverless = require('../../../Serverless'); const testUtils = require('../../../../tests/utils'); describe('AwsDeployFunction', () => { + let AwsDeployFunction; let serverless; let awsDeployFunction; + let cryptoStub; beforeEach(() => { serverless = new Serverless(); @@ -44,6 +46,14 @@ describe('AwsDeployFunction', () => { }; serverless.init(); serverless.setProvider('aws', new AwsProvider(serverless)); + cryptoStub = { + createHash: function () { return this; }, // eslint-disable-line + update: function () { return this; }, // eslint-disable-line + digest: sinon.stub(), + }; + AwsDeployFunction = proxyquire('./index.js', { + crypto: cryptoStub, + }); awsDeployFunction = new AwsDeployFunction(serverless, options); }); @@ -61,15 +71,24 @@ describe('AwsDeployFunction', () => { }); describe('#checkIfFunctionExists()', () => { + let getFunctionStub; + + beforeEach(() => { + getFunctionStub = sinon + .stub(awsDeployFunction.provider, 'request') + .resolves({ func: { name: 'first' } }); + }); + + afterEach(() => { + awsDeployFunction.provider.request.restore(); + }); + it('it should throw error if function is not provided', () => { serverless.service.functions = null; expect(() => awsDeployFunction.checkIfFunctionExists()).to.throw(Error); }); - it('should check if the function is deployed', () => { - const getFunctionStub = sinon - .stub(awsDeployFunction.provider, 'request').resolves(); - + it('should check if the function is deployed and save the result', () => { awsDeployFunction.serverless.service.functions = { first: { name: 'first', @@ -88,30 +107,57 @@ describe('AwsDeployFunction', () => { awsDeployFunction.options.stage, awsDeployFunction.options.region )).to.be.equal(true); - awsDeployFunction.provider.request.restore(); + expect(awsDeployFunction.serverless.service.provider.remoteFunctionData).to.deep.equal({ + func: { + name: 'first', + }, + }); }); }); }); describe('#deployFunction()', () => { let artifactFilePath; + let updateFunctionCodeStub; + let statSyncStub; + let readFileSyncStub; beforeEach(() => { // write a file to disc to simulate that the deployment artifact exists awsDeployFunction.packagePath = testUtils.getTmpDirPath(); artifactFilePath = path.join(awsDeployFunction.packagePath, 'first.zip'); serverless.utils.writeFileSync(artifactFilePath, 'first.zip file content'); + updateFunctionCodeStub = sinon + .stub(awsDeployFunction.provider, 'request') + .resolves(); + statSyncStub = sinon + .stub(fs, 'statSync') + .returns({ size: 1024 }); + sinon.spy(awsDeployFunction.serverless.cli, 'log'); + readFileSyncStub = sinon + .stub(fs, 'readFileSync') + .returns(); + awsDeployFunction.serverless.service.provider.remoteFunctionData = { + Configuration: { + CodeSha256: 'remote-hash-zip-file', + }, + }; }); - it('should deploy the function', () => { - // deploy the function artifact not the service artifact - const updateFunctionCodeStub = sinon - .stub(awsDeployFunction.provider, 'request').resolves(); + afterEach(() => { + awsDeployFunction.provider.request.restore(); + fs.statSync.restore(); + fs.readFileSync.restore(); + }); + + it('should deploy the function if the hashes are different', () => { + cryptoStub.createHash().update().digest.onCall(0).returns('local-hash-zip-file'); return awsDeployFunction.deployFunction().then(() => { const data = fs.readFileSync(artifactFilePath); expect(updateFunctionCodeStub.calledOnce).to.be.equal(true); + expect(readFileSyncStub.called).to.equal(true); expect(updateFunctionCodeStub.calledWithExactly( 'Lambda', 'updateFunctionCode', @@ -122,22 +168,95 @@ describe('AwsDeployFunction', () => { awsDeployFunction.options.stage, awsDeployFunction.options.region )).to.be.equal(true); - awsDeployFunction.provider.request.restore(); + expect(readFileSyncStub.calledWithExactly(artifactFilePath)).to.equal(true); + }); + }); + + it('should deploy the function if the hashes are same but the "force" option is used', () => { + awsDeployFunction.options.force = true; + cryptoStub.createHash().update().digest.onCall(0).returns('remote-hash-zip-file'); + + return awsDeployFunction.deployFunction().then(() => { + const data = fs.readFileSync(artifactFilePath); + + expect(updateFunctionCodeStub.calledOnce).to.be.equal(true); + expect(readFileSyncStub.called).to.equal(true); + expect(updateFunctionCodeStub.calledWithExactly( + 'Lambda', + 'updateFunctionCode', + { + FunctionName: 'first', + ZipFile: data, + }, + awsDeployFunction.options.stage, + awsDeployFunction.options.region + )).to.be.equal(true); + expect(readFileSyncStub.calledWithExactly(artifactFilePath)).to.equal(true); + }); + }); + + it('should resolve if the hashes are the same', () => { + cryptoStub.createHash().update().digest.onCall(0).returns('remote-hash-zip-file'); + + return awsDeployFunction.deployFunction().then(() => { + const expected = 'Code not changed. Skipping function deployment.'; + + expect(updateFunctionCodeStub.calledOnce).to.be.equal(false); + expect(readFileSyncStub.calledOnce).to.equal(true); + expect(awsDeployFunction.serverless.cli.log.calledWithExactly(expected)).to.equal(true); + expect(readFileSyncStub.calledWithExactly(artifactFilePath)).to.equal(true); }); }); it('should log artifact size', () => { - sinon.stub(fs, 'statSync').returns({ size: 1024 }); - sinon.stub(awsDeployFunction.provider, 'request').resolves(); - sinon.spy(awsDeployFunction.serverless.cli, 'log'); + // awnY7Oi280gp5kTCloXzsqJCO4J766x6hATWqQsN/uM= <-- hash of the local zip file + readFileSyncStub.returns(new Buffer('my-service.zip content')); return awsDeployFunction.deployFunction().then(() => { const expected = 'Uploading function: first (1 KB)...'; - expect(awsDeployFunction.serverless.cli.log.calledWithExactly(expected)).to.be.equal(true); - awsDeployFunction.provider.request.restore(); - fs.statSync.restore(); + expect(readFileSyncStub.calledOnce).to.equal(true); + expect(statSyncStub.calledOnce).to.equal(true); + expect(awsDeployFunction.serverless.cli.log.calledWithExactly(expected)).to.be.equal(true); + expect(readFileSyncStub.calledWithExactly(artifactFilePath)).to.equal(true); }); }); + + describe('when artifact is provided', () => { + let getFunctionStub; + const artifactZipFile = 'artifact.zip'; + + beforeEach(() => { + getFunctionStub = sinon.stub(serverless.service, 'getFunction').returns({ + handler: true, + package: { + artifact: artifactZipFile, + }, + }); + }); + + afterEach(() => { + serverless.service.getFunction.restore(); + }); + + it('should read the provided artifact', () => awsDeployFunction.deployFunction().then(() => { + const data = fs.readFileSync(artifactZipFile); + + expect(readFileSyncStub).to.have.been.calledWithExactly(artifactZipFile); + expect(statSyncStub).to.have.been.calledWithExactly(artifactZipFile); + expect(getFunctionStub).to.have.been.calledWithExactly('first'); + expect(updateFunctionCodeStub.calledOnce).to.equal(true); + expect(updateFunctionCodeStub.calledWithExactly( + 'Lambda', + 'updateFunctionCode', + { + FunctionName: 'first', + ZipFile: data, + }, + awsDeployFunction.options.stage, + awsDeployFunction.options.region + )).to.be.equal(true); + })); + }); }); }); diff --git a/lib/plugins/aws/lib/normalizeFiles.js b/lib/plugins/aws/lib/normalizeFiles.js new file mode 100644 index 000000000..0c3a6dcde --- /dev/null +++ b/lib/plugins/aws/lib/normalizeFiles.js @@ -0,0 +1,19 @@ +'use strict'; + +const _ = require('lodash'); + +module.exports = { + normalizeCloudFormationTemplate(template) { + const normalizedTemplate = _.cloneDeep(template); + + // reset all the S3Keys for AWS::Lambda::Function resources + _.forEach(normalizedTemplate.Resources, (value) => { + if (value.Type && value.Type === 'AWS::Lambda::Function') { + const newVal = value; + newVal.Properties.Code.S3Key = ''; + } + }); + + return normalizedTemplate; + }, +}; diff --git a/lib/plugins/aws/lib/normalizeFiles.test.js b/lib/plugins/aws/lib/normalizeFiles.test.js new file mode 100644 index 000000000..de1020f09 --- /dev/null +++ b/lib/plugins/aws/lib/normalizeFiles.test.js @@ -0,0 +1,58 @@ +'use strict'; + +const expect = require('chai').expect; +const normalizeFiles = require('./normalizeFiles'); + +describe('normalizeFiles', () => { + describe('#normalizeCloudFormationTemplate()', () => { + it('should reset the S3 code keys for Lambda functions', () => { + const input = { + Resources: { + MyLambdaFunction: { + Type: 'AWS::Lambda::Function', + Properties: { + Code: { + S3Key: 'some-s3-key-for-the-code', + }, + }, + }, + }, + }; + + const result = normalizeFiles.normalizeCloudFormationTemplate(input); + + expect(result).to.deep.equal({ + Resources: { + MyLambdaFunction: { + Type: 'AWS::Lambda::Function', + Properties: { + Code: { + S3Key: '', + }, + }, + }, + }, + }); + }); + + it('should keep other resources untouched', () => { + const input = { + Resources: { + MyOtherResource: { + Type: 'AWS::XXX::XXX', + }, + }, + }; + + const result = normalizeFiles.normalizeCloudFormationTemplate(input); + + expect(result).to.deep.equal({ + Resources: { + MyOtherResource: { + Type: 'AWS::XXX::XXX', + }, + }, + }); + }); + }); +}); diff --git a/lib/plugins/aws/provider/awsProvider.js b/lib/plugins/aws/provider/awsProvider.js index c7354fb43..2bea7448a 100644 --- a/lib/plugins/aws/provider/awsProvider.js +++ b/lib/plugins/aws/provider/awsProvider.js @@ -146,11 +146,22 @@ class AwsProvider { f() .then(resolve) .catch((e) => { - if (e.statusCode === 429) { + const err = e; + if (err.statusCode === 429) { that.serverless.cli.log("'Too many requests' received, sleeping 5 seconds"); setTimeout(doCall, 5000); } else { - reject(e); + if (err.message.match(/(.+security token.+is )+(invalid)*|(expired)*/)) { + const errorMessage = [ + 'The AWS security token included in the request is invalid / expired.\n', + ' Please re-authenticate if you\'re using MFA.\n', + ' Or check your ~./aws/credentials file and verify your keys are correct.\n', + ' More information on setting up credentials', + ` can be found here: ${chalk.green('https://git.io/vXsdd')}.`, + ].join(''); + err.message = errorMessage; + } + reject(new this.serverless.classes.Error(err.message, err.statusCode)); } }); }; diff --git a/lib/plugins/aws/provider/awsProvider.test.js b/lib/plugins/aws/provider/awsProvider.test.js index f4b8e7705..d796dd19e 100644 --- a/lib/plugins/aws/provider/awsProvider.test.js +++ b/lib/plugins/aws/provider/awsProvider.test.js @@ -3,6 +3,7 @@ const expect = require('chai').expect; const proxyquire = require('proxyquire'); const sinon = require('sinon'); +const chalk = require('chalk'); const AwsProvider = require('./awsProvider'); const Serverless = require('../../../Serverless'); @@ -214,6 +215,43 @@ describe('AwsProvider', () => { .catch(() => done()); }); + it('should ask to re-authenticate MFA or check if AWS credentials are valid', (done) => { + const error = { + statusCode: 403, + message: 'The security token included in the request is invalid', + }; + class FakeS3 { + constructor(credentials) { + this.credentials = credentials; + } + + error() { + return { + send(cb) { + cb(error); + }, + }; + } + } + awsProvider.sdk = { + S3: FakeS3, + }; + awsProvider.request('S3', 'error', {}) + .then(() => done('Should not succeed')) + .catch((err) => { + const errorMessage = [ + 'The AWS security token included in the request is invalid / expired.\n', + ' Please re-authenticate if you\'re using MFA.\n', + ' Or check your ~./aws/credentials file and verify your keys are correct.\n', + ' More information on setting up credentials', + ` can be found here: ${chalk.green('https://git.io/vXsdd')}.`, + ].join(''); + expect(err.message).to.equal(errorMessage); + done(); + }) + .catch(done); + }); + it('should return ref to docs for missing credentials', (done) => { const error = { statusCode: 403, diff --git a/lib/plugins/create/templates/aws-fsharp/build.sh b/lib/plugins/create/templates/aws-fsharp/build.sh index 892b0f289..f57aebe45 100644 --- a/lib/plugins/create/templates/aws-fsharp/build.sh +++ b/lib/plugins/create/templates/aws-fsharp/build.sh @@ -1,8 +1,13 @@ #!/bin/bash +isMacOs=`uname -a | grep Darwin` + #install zip -apt-get -qq update -apt-get -qq -y install zip +if [ -z "$isMacOs" ] +then + apt-get -qq update + apt-get -qq -y install zip +fi dotnet restore diff --git a/lib/plugins/deploy/deploy.js b/lib/plugins/deploy/deploy.js index bdb917acd..5290b3247 100644 --- a/lib/plugins/deploy/deploy.js +++ b/lib/plugins/deploy/deploy.js @@ -44,6 +44,9 @@ class Deploy { usage: 'Show all stack events during deployment', shortcut: 'v', }, + force: { + usage: 'Forces a deployment to take place', + }, }, commands: { function: { @@ -67,6 +70,9 @@ class Deploy { usage: 'Region of the function', shortcut: 'r', }, + force: { + usage: 'Forces a deployment to take place', + }, }, }, list: { diff --git a/lib/plugins/package/lib/packageService.js b/lib/plugins/package/lib/packageService.js index 4d757201e..b232eaf19 100644 --- a/lib/plugins/package/lib/packageService.js +++ b/lib/plugins/package/lib/packageService.js @@ -1,6 +1,7 @@ 'use strict'; const BbPromise = require('bluebird'); +const path = require('path'); const _ = require('lodash'); module.exports = { @@ -35,7 +36,10 @@ module.exports = { const functionObject = this.serverless.service.getFunction(functionName); functionObject.package = functionObject.package || {}; if (functionObject.package.disable) { - this.serverless.cli.log('Packaging disabled for function: ' + functionName); + this.serverless.cli.log(`Packaging disabled for function: "${functionName}"`); + return BbPromise.resolve(); + } + if (functionObject.package.artifact) { return BbPromise.resolve(); } if (functionObject.package.individually || this.serverless.service @@ -47,7 +51,7 @@ module.exports = { }); return BbPromise.all(packagePromises).then(() => { - if (shouldPackageService) { + if (shouldPackageService && !this.serverless.service.package.artifact) { return this.packageAll(); } return BbPromise.resolve(); @@ -74,12 +78,29 @@ module.exports = { const functionObject = this.serverless.service.getFunction(functionName); const funcPackageConfig = functionObject.package || {}; + // use the artifact in function config if provided + if (funcPackageConfig.artifact) { + const filePath = path.join(this.serverless.config.servicePath, funcPackageConfig.artifact); + functionObject.package.artifact = filePath; + return BbPromise.resolve(filePath); + } + + // use the artifact in service config if provided + if (this.serverless.service.package.artifact) { + const filePath = path.join(this.serverless.config.servicePath, + this.serverless.service.package.artifact); + funcPackageConfig.artifact = filePath; + return BbPromise.resolve(filePath); + } + const exclude = this.getExcludes(funcPackageConfig.exclude); const include = this.getIncludes(funcPackageConfig.include); const zipFileName = `${functionName}.zip`; return this.zipService(exclude, include, zipFileName).then(artifactPath => { - functionObject.artifact = artifactPath; + functionObject.package = { + artifact: artifactPath, + }; return artifactPath; }); }, diff --git a/lib/plugins/package/lib/packageService.test.js b/lib/plugins/package/lib/packageService.test.js index 262ef03f8..f3da7f193 100644 --- a/lib/plugins/package/lib/packageService.test.js +++ b/lib/plugins/package/lib/packageService.test.js @@ -161,13 +161,24 @@ describe('#packageService()', () => { )); }); - it('should not package service with only disabled functions', () => { + it('should not package functions if package artifact specified', () => { + serverless.service.package.artifact = 'some/file.zip'; + + const packageAllStub = sinon.stub(packagePlugin, 'packageAll').resolves(); + + return expect(packagePlugin.packageService()).to.be.fulfilled + .then(() => expect(packageAllStub).to.not.be.called); + }); + + it('should package functions individually if package artifact specified', () => { + serverless.service.package.artifact = 'some/file.zip'; + serverless.service.package.individually = true; serverless.service.functions = { 'test-one': { name: 'test-one', - package: { - disable: true, - }, + }, + 'test-two': { + name: 'test-two', }, }; @@ -178,10 +189,36 @@ describe('#packageService()', () => { return expect(packagePlugin.packageService()).to.be.fulfilled .then(() => BbPromise.join( - expect(packageFunctionStub).to.not.be.calledOnce, - expect(packageAllStub).to.not.be.calledOnce + expect(packageFunctionStub).to.be.calledTwice, + expect(packageAllStub).to.not.be.called )); }); + + it('should package single functions individually if package artifact specified', () => { + serverless.service.package.artifact = 'some/file.zip'; + serverless.service.functions = { + 'test-one': { + name: 'test-one', + package: { + individually: true, + }, + }, + 'test-two': { + name: 'test-two', + }, + }; + + const packageFunctionStub = sinon + .stub(packagePlugin, 'packageFunction').resolves((func) => func.name); + const packageAllStub = sinon + .stub(packagePlugin, 'packageAll').resolves((func) => func.name); + + return expect(packagePlugin.packageService()).to.be.fulfilled + .then(() => BbPromise.join( + expect(packageFunctionStub).to.be.calledOnce, + expect(packageAllStub).to.not.be.called + )); + }); }); describe('#packageAll()', () => { @@ -273,5 +310,49 @@ describe('#packageService()', () => { ), ])); }); + + it('should return function artifact file path', () => { + const servicePath = 'test'; + const funcName = 'test-func'; + + serverless.config.servicePath = servicePath; + serverless.service.functions = {}; + serverless.service.functions[funcName] = { + name: `test-proj-${funcName}`, + package: { + artifact: 'artifact.zip', + }, + }; + + return expect(packagePlugin.packageFunction(funcName)).to.eventually + .equal('test/artifact.zip') + .then(() => BbPromise.all([ + expect(getExcludesStub).to.not.have.been.called, + expect(getIncludesStub).to.not.have.been.called, + expect(zipServiceStub).to.not.have.been.called, + ])); + }); + + it('should return service artifact file path', () => { + const servicePath = 'test'; + const funcName = 'test-func'; + + serverless.config.servicePath = servicePath; + serverless.service.functions = {}; + serverless.service.package = { + artifact: 'artifact.zip', + }; + serverless.service.functions[funcName] = { + name: `test-proj-${funcName}`, + }; + + return expect(packagePlugin.packageFunction(funcName)).to.eventually + .equal('test/artifact.zip') + .then(() => BbPromise.all([ + expect(getExcludesStub).to.not.have.been.called, + expect(getIncludesStub).to.not.have.been.called, + expect(zipServiceStub).to.not.have.been.called, + ])); + }); }); }); diff --git a/lib/plugins/package/lib/zipService.js b/lib/plugins/package/lib/zipService.js index 6ad97efe9..a3847d967 100644 --- a/lib/plugins/package/lib/zipService.js +++ b/lib/plugins/package/lib/zipService.js @@ -27,10 +27,18 @@ module.exports = { excludeDevDependencies(params) { const servicePath = this.serverless.config.servicePath; - const exAndInNode = excludeNodeDevDependencies(servicePath); - params.exclude = _.union(params.exclude, exAndInNode.exclude); - params.include = _.union(params.include, exAndInNode.include); + let excludeDevDependencies = this.serverless.service.package.excludeDevDependencies; + if (excludeDevDependencies === undefined || excludeDevDependencies === null) { + excludeDevDependencies = true; + } + + if (excludeDevDependencies) { + const exAndInNode = excludeNodeDevDependencies(servicePath); + + params.exclude = _.union(params.exclude, exAndInNode.exclude); + params.include = _.union(params.include, exAndInNode.include); + } return BbPromise.resolve(params); }, @@ -90,6 +98,7 @@ module.exports = { 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 }); } }); @@ -139,7 +148,8 @@ function excludeNodeDevDependencies(servicePath) { .execSync('npm ls --prod=true --parseable=true --silent') .toString().trim(); - const prodDependencyPaths = prodDependencies.match(/(node_modules\/.*)/g); + const nodeModulesRegex = new RegExp(`${path.join('node_modules', path.sep)}.*`, 'g'); + const prodDependencyPaths = prodDependencies.match(nodeModulesRegex); let pathToDep = ''; // if the package.json file is not in the root of the service path diff --git a/lib/plugins/package/lib/zipService.test.js b/lib/plugins/package/lib/zipService.test.js index ae7df3331..37c79e14f 100644 --- a/lib/plugins/package/lib/zipService.test.js +++ b/lib/plugins/package/lib/zipService.test.js @@ -68,6 +68,15 @@ describe('zipService', () => { }); describe('#excludeDevDependencies()', () => { + it('should resolve when opted out of dev dependency exclusion', () => { + packagePlugin.serverless.service.package.excludeDevDependencies = false; + + return expect(packagePlugin.excludeDevDependencies(params)).to.be + .fulfilled.then((updatedParams) => { + expect(updatedParams).to.deep.equal(params); + }); + }); + describe('when dealing with Node.js runtimes', () => { let globbySyncStub; let processChdirStub; diff --git a/package-lock.json b/package-lock.json index b81c4dfcc..f87f0a346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,8 @@ { "name": "serverless", - "version": "1.16.1", + "version": "1.17.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/async": { "version": "2.0.40", @@ -21,10 +22,66 @@ "integrity": "sha1-PDSD5gbAQTeEOOlRRk8A5OYHBtY=", "optional": true }, + "abab": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz", + "integrity": "sha1-uB3l9ydOxOdW15fNg08wNkJyTl0=", + "dev": true + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "acorn": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", + "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==", + "dev": true + }, + "acorn-globals": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", + "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "dev": true, + "requires": { + "acorn": "4.0.13" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "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.3.0" + }, + "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 + } + } + }, "agent-base": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "requires": { + "extend": "3.0.1", + "semver": "5.0.3" + }, "dependencies": { "semver": { "version": "5.0.3", @@ -33,6 +90,39 @@ } } }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, "ansi": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", @@ -43,6 +133,15 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -53,48 +152,179 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "ansicolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.2.1.tgz", + "integrity": "sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=", + "dev": true + }, "apollo-client": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/apollo-client/-/apollo-client-1.4.2.tgz", - "integrity": "sha1-PUnRmu+guvkO3uVAGjWOQzpuYk8=" + "integrity": "sha1-PUnRmu+guvkO3uVAGjWOQzpuYk8=", + "requires": { + "@types/async": "2.0.40", + "@types/graphql": "0.9.1", + "@types/isomorphic-fetch": "0.0.34", + "graphql": "0.10.1", + "graphql-anywhere": "3.1.0", + "graphql-tag": "2.4.0", + "redux": "3.7.0", + "symbol-observable": "1.0.4", + "whatwg-fetch": "2.0.3" + } + }, + "append-transform": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true, + "requires": { + "default-require-extensions": "1.0.0" + } }, "archiver": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz", "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=", + "requires": { + "archiver-utils": "1.3.0", + "async": "2.4.1", + "buffer-crc32": "0.2.13", + "glob": "7.1.2", + "lodash": "4.17.4", + "readable-stream": "2.2.11", + "tar-stream": "1.5.4", + "walkdir": "0.0.11", + "zip-stream": "1.1.1" + }, "dependencies": { "async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/async/-/async-2.4.1.tgz", - "integrity": "sha1-YqVrJ5yYoR0JhwlqAcw+6463u9c=" + "integrity": "sha1-YqVrJ5yYoR0JhwlqAcw+6463u9c=", + "requires": { + "lodash": "4.17.4" + } } } }, "archiver-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", - "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=" + "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "requires": { + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "lazystream": "1.0.0", + "lodash": "4.17.4", + "normalize-path": "2.1.1", + "readable-stream": "2.2.11" + } }, "are-we-there-yet": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=" + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.2.11" + } }, "argparse": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=" + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=" + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "1.0.3" + } }, "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "array.prototype.find": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", + "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.7.0" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz", + "integrity": "sha1-UidltQw1EEkOUtfc/ghe+bqWlY8=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true + }, "async": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", @@ -105,10 +335,27 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "autolinker": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.15.3.tgz", + "integrity": "sha1-NCQX2PLzRhsUzwkIjV7fh5HcmDI=", + "dev": true + }, "aws-sdk": { "version": "2.67.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.67.0.tgz", "integrity": "sha1-wPw6Q0PPxjEmXZ3WvFC6cJQB+Fc=", + "requires": { + "buffer": "5.0.6", + "crypto-browserify": "1.0.9", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.0.1", + "xml2js": "0.4.17", + "xmlbuilder": "4.2.1" + }, "dependencies": { "uuid": { "version": "3.0.1", @@ -117,6 +364,218 @@ } } }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "babel-code-frame": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.1" + } + }, + "babel-core": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz", + "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "babel-generator": "6.25.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.24.1", + "babel-runtime": "6.23.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "convert-source-map": "1.5.0", + "debug": "2.6.8", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.7", + "slash": "1.0.0", + "source-map": "0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz", + "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.6", + "trim-right": "1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-template": "6.25.0" + } + }, + "babel-jest": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-18.0.0.tgz", + "integrity": "sha1-F+u6jLMoXJBthZ6HB+Tnl5X7ZeM=", + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-plugin-istanbul": "3.1.2", + "babel-preset-jest": "18.0.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0" + } + }, + "babel-plugin-istanbul": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-3.1.2.tgz", + "integrity": "sha1-EdWr3hhCXsJLXWSMfgtdJc01SiI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "istanbul-lib-instrument": "1.7.3", + "object-assign": "4.1.1", + "test-exclude": "3.3.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-18.0.0.tgz", + "integrity": "sha1-QVDnDsq1YObnNErchJSYBy004So=", + "dev": true + }, + "babel-preset-jest": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-18.0.0.tgz", + "integrity": "sha1-hPr4yj7GWrp9Xj9Zu67ZNaskBJ4=", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "18.0.0" + } + }, + "babel-register": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz", + "integrity": "sha1-fhDhOi9xBlvfrVoXh7pFvKbe118=", + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-runtime": "6.23.0", + "core-js": "2.4.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.15" + } + }, + "babel-runtime": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", + "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", + "dev": true, + "requires": { + "core-js": "2.4.1", + "regenerator-runtime": "0.10.5" + } + }, + "babel-template": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz", + "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz", + "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.23.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "debug": "2.6.8", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "babel-types": { + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz", + "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=", + "dev": true, + "requires": { + "babel-runtime": "6.23.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.17.4", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz", + "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==", + "dev": true + }, "balanced-match": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", @@ -127,75 +586,322 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz", "integrity": "sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=" }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, "bl": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", - "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=" + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "requires": { + "readable-stream": "2.2.11" + } }, "bluebird": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, "brace-expansion": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", - "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=" + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "browser-resolve": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", + "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "bser": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", + "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", + "dev": true, + "requires": { + "node-int64": "0.4.0" + } }, "buffer": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.0.6.tgz", - "integrity": "sha1-LqZp9+7Atu2gWwj4tf9mGyhXNYg=" + "integrity": "sha1-LqZp9+7Atu2gWwj4tf9mGyhXNYg=", + "requires": { + "base64-js": "1.2.0", + "ieee754": "1.1.8" + } }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caller-id": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-id/-/caller-id-0.1.0.tgz", + "integrity": "sha1-Wb2sCJPRLDhxQIJ5Ix+XRYNk8Hs=", + "dev": true, + "requires": { + "stack-trace": "0.0.9" + } + }, + "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" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, "capture-stack-trace": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" }, + "cardinal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-1.0.0.tgz", + "integrity": "sha1-UOIcGwqjdyn5N33vGWtanOyTLuk=", + "dev": true, + "requires": { + "ansicolors": "0.2.1", + "redeyed": "1.0.1" + } + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, "caw": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.0.tgz", - "integrity": "sha1-Efi93C+AFGmVLV4yJbqYSVovoP8=" + "integrity": "sha1-Efi93C+AFGmVLV4yJbqYSVovoP8=", + "requires": { + "get-proxy": "1.1.0", + "tunnel-agent": "0.4.3" + } + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true, + "requires": { + "assertion-error": "1.0.2", + "deep-eql": "0.1.3", + "type-detect": "1.0.0" + } + }, + "chai-as-promised": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-6.0.0.tgz", + "integrity": "sha1-GgKkM6byTa+sY7nJb6FoTbGqjaY=", + "dev": true, + "requires": { + "check-error": "1.0.2" + } }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=" + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true }, "ci-info": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.0.0.tgz", "integrity": "sha1-3FKF8rTiUYIWg2gcOBwziPRuxTQ=" }, + "circular-json": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", + "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=", + "dev": true + }, "cli-cursor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=" + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "requires": { + "restore-cursor": "1.0.1" + } + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + } + }, + "cli-usage": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/cli-usage/-/cli-usage-0.1.4.tgz", + "integrity": "sha1-fAHg3HBsI0s5yTODjI4gshdXduI=", + "dev": true, + "requires": { + "marked": "0.3.6", + "marked-terminal": "1.7.0" + } }, "cli-width": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=" }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + } + } + }, + "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", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, + "coffee-script": { + "version": "1.12.6", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.6.tgz", + "integrity": "sha1-KFo/cRVokGUGTWv570Vy22ZpXL8=", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, "combined-stream": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=" + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } }, "commander": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", - "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=" + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": "1.0.1" + } }, "component-emitter": { "version": "1.2.1", @@ -205,7 +911,13 @@ "compress-commons": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.0.tgz", - "integrity": "sha1-WFhwku8g03y1i68AARLJJ4/3O58=" + "integrity": "sha1-WFhwku8g03y1i68AARLJJ4/3O58=", + "requires": { + "buffer-crc32": "0.2.13", + "crc32-stream": "2.0.0", + "normalize-path": "2.1.1", + "readable-stream": "2.2.11" + } }, "concat-map": { "version": "0.0.1", @@ -215,7 +927,30 @@ "concat-stream": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=" + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.2.11", + "typedarray": "0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "content-type-parser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", + "integrity": "sha1-w+VpiMU8ZRJ/tG1AMqOpACRv3JQ=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true }, "cookie": { "version": "0.3.1", @@ -227,11 +962,30 @@ "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=" }, + "core-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "coveralls": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.13.1.tgz", + "integrity": "sha1-1wu5rMGDXsTwY/+drFQjwXsR8Xg=", + "dev": true, + "requires": { + "js-yaml": "3.8.4", + "lcov-parse": "0.0.10", + "log-driver": "1.2.5", + "minimist": "1.2.0", + "request": "2.79.0" + } + }, "crc": { "version": "3.4.4", "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz", @@ -240,42 +994,142 @@ "crc32-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", - "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=" + "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", + "requires": { + "crc": "3.4.4", + "readable-stream": "2.2.11" + } }, "create-error-class": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=" + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "requires": { + "capture-stack-trace": "1.0.0" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } }, "crypto-browserify": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz", "integrity": "sha1-zFRJaF37hesRyYKKzHy4erW7/MA=" }, + "cssom": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", + "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", + "dev": true + }, + "cssstyle": { + "version": "0.2.37", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", + "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", + "dev": true, + "requires": { + "cssom": "0.3.2" + } + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "0.10.23" + } + }, + "damerau-levenshtein": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz", + "integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, "debug": { "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=" + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true }, "decompress": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", - "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=" + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "requires": { + "decompress-tar": "4.1.0", + "decompress-tarbz2": "4.1.0", + "decompress-targz": "4.1.0", + "decompress-unzip": "4.0.1", + "graceful-fs": "4.1.11", + "make-dir": "1.0.0", + "pify": "2.3.0", + "strip-dirs": "2.0.0" + } }, "decompress-tar": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.0.tgz", - "integrity": "sha1-HwkqtphEBVjHL8eOd9JG0+y0U7A=" + "integrity": "sha1-HwkqtphEBVjHL8eOd9JG0+y0U7A=", + "requires": { + "file-type": "3.9.0", + "is-stream": "1.1.0", + "tar-stream": "1.5.4" + } }, "decompress-tarbz2": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.0.tgz", - "integrity": "sha1-+6tY1d5z8/0hPKw68cGDNPUcuJE=" + "integrity": "sha1-+6tY1d5z8/0hPKw68cGDNPUcuJE=", + "requires": { + "decompress-tar": "4.1.0", + "file-type": "3.9.0", + "is-stream": "1.1.0", + "pify": "2.3.0", + "seek-bzip": "1.0.5", + "unbzip2-stream": "1.2.4" + } }, "decompress-targz": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.0.tgz", "integrity": "sha1-R1ucQGvmIa6DYnSALZsl+ZE+rVk=", + "requires": { + "decompress-tar": "4.1.0", + "file-type": "4.4.0", + "is-stream": "1.1.0" + }, "dependencies": { "file-type": { "version": "4.4.0", @@ -288,11 +1142,38 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "requires": { + "file-type": "3.9.0", + "get-stream": "2.3.1", + "pify": "2.3.0", + "yauzl": "2.8.0" + }, "dependencies": { "get-stream": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", - "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=" + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "requires": { + "object-assign": "4.1.1", + "pinkie-promise": "2.0.1" + } + } + } + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true } } }, @@ -301,6 +1182,63 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=" }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.0.tgz", + "integrity": "sha512-Hm4+NyDQGgH3oYhKqR0gd99veBBZpnEUNoEfFl+3PRkQL+LKGJEBgqimeofAWzUn6aBzcaYPJrRigto/WfDzTg==", + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "dev": true, + "requires": { + "strip-bom": "2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + } + } + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "6.1.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.1" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -311,66 +1249,558 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "diacritics-map": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz", + "integrity": "sha1-bfwP+dAQAKLt8oZTccrDFulJd68=", + "dev": true + }, + "diff": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.0.tgz", + "integrity": "sha512-w0XZubFWn0Adlsapj9EAWX0FqWdO4tz8kc3RiYdWLh4k/V8PTb6i0SMgXt0vRM3zyKnT8tKO7mUlieRQHIjMNg==", + "dev": true + }, + "doctrine": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", + "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, "download": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/download/-/download-5.0.3.tgz", - "integrity": "sha1-Y1N/l3+ZJmow64oqL70fILgAD3o=" + "integrity": "sha1-Y1N/l3+ZJmow64oqL70fILgAD3o=", + "requires": { + "caw": "2.0.0", + "decompress": "4.2.0", + "filenamify": "2.0.0", + "get-stream": "3.0.0", + "got": "6.7.1", + "mkdirp": "0.5.1", + "pify": "2.3.0" + } }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, "encoding": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=" + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "0.4.17" + } }, "end-of-stream": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", - "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=" + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "requires": { + "once": "1.4.0" + } + }, + "errno": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", + "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", + "dev": true, + "requires": { + "prr": "0.0.0" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.7.0.tgz", + "integrity": "sha1-363ndOAb/Nl/lhgCmMRJyGI/uUw=", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.0", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "es5-ext": { + "version": "0.10.23", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.23.tgz", + "integrity": "sha1-dXi1G+l0IHpUh4IbVlOMIk5Oezg=", + "dev": true, + "requires": { + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } + }, + "es6-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23", + "es6-symbol": "3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23", + "es6-iterator": "2.0.1", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23", + "es6-iterator": "2.0.1", + "es6-symbol": "3.1.1" + } }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "3.1.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" + }, + "dependencies": { + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "chalk": "1.1.3", + "concat-stream": "1.6.0", + "debug": "2.6.8", + "doctrine": "2.0.0", + "escope": "3.6.0", + "espree": "3.4.3", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.3", + "imurmurhash": "0.1.4", + "inquirer": "1.2.3", + "is-my-json-valid": "2.16.0", + "is-resolvable": "1.0.0", + "js-yaml": "3.8.4", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.6.1", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" + } + }, + "eslint-config-airbnb": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-10.0.1.tgz", + "integrity": "sha1-pHAQhkbWxF4fY5oD8R1QShqkrtw=", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "5.0.3" + } + }, + "eslint-config-airbnb-base": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-5.0.3.tgz", + "integrity": "sha1-lxSsNews1/qw1E0Uip+R2ylEB00=", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", + "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=", + "dev": true, + "requires": { + "debug": "2.6.8", + "object-assign": "4.1.1", + "resolve": "1.3.3" + } + }, + "eslint-plugin-import": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-1.16.0.tgz", + "integrity": "sha1-svoH68xTUE0PKkR3WC7Iv/GHG58=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1", + "contains-path": "0.1.0", + "debug": "2.6.8", + "doctrine": "1.3.0", + "es6-map": "0.1.5", + "es6-set": "0.1.5", + "eslint-import-resolver-node": "0.2.3", + "has": "1.0.1", + "lodash.cond": "4.5.2", + "lodash.endswith": "4.2.1", + "lodash.find": "4.6.0", + "lodash.findindex": "4.6.0", + "minimatch": "3.0.4", + "object-assign": "4.1.1", + "pkg-dir": "1.0.0", + "pkg-up": "1.0.0" + }, + "dependencies": { + "doctrine": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.3.0.tgz", + "integrity": "sha1-E+dWgrVVGEJCdvfBc3g0Vu+RPSY=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-2.2.3.tgz", + "integrity": "sha1-TjXLcbin23AqxBXIBuuOjZ6mxl0=", + "dev": true, + "requires": { + "damerau-levenshtein": "1.0.4", + "jsx-ast-utils": "1.4.1", + "object-assign": "4.1.1" + } + }, + "eslint-plugin-react": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", + "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", + "dev": true, + "requires": { + "array.prototype.find": "2.0.4", + "doctrine": "1.5.0", + "has": "1.0.1", + "jsx-ast-utils": "1.4.1", + "object.assign": "4.0.4" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "espree": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", + "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", + "dev": true, + "requires": { + "acorn": "5.1.1", + "acorn-jsx": "3.0.1" + } + }, "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.23" + } + }, + "exec-sh": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.0.tgz", + "integrity": "sha1-FPdd4/INKG75MwmbLOUKkDWc7xA=", + "dev": true, + "requires": { + "merge": "1.2.0" + } + }, "exit-hook": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=" }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, "external-editor": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz", - "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=" + "integrity": "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=", + "requires": { + "extend": "3.0.1", + "spawn-sync": "1.0.15", + "tmp": "0.0.29" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fb-watchman": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", + "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", + "dev": true, + "requires": { + "bser": "1.0.2" + } }, "fd-slicer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=" + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "requires": { + "pend": "1.2.0" + } }, "figures": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=" + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "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.2", + "object-assign": "4.1.1" + } }, "file-type": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=" }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, "filename-reserved-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", @@ -379,17 +1809,118 @@ "filenamify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.0.0.tgz", - "integrity": "sha1-vRYiYsC26Uv7zc8Zo7uzdk94VpU=" + "integrity": "sha1-vRYiYsC26Uv7zc8Zo7uzdk94VpU=", + "requires": { + "filename-reserved-regex": "2.0.0", + "strip-outer": "1.0.0", + "trim-repeated": "1.0.0" + } + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "7.1.2", + "minimatch": "3.0.4" + } }, "filesize": { "version": "3.5.10", "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.5.10.tgz", "integrity": "sha1-/I+iPdtO+eXgq24eZPZ5okpWdh8=" }, + "fill-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", + "integrity": "sha1-mo+jb06K1jTjv2tPPIiCVRRS6yA=", + "dev": true, + "requires": { + "is-object": "1.0.1", + "merge-descriptors": "1.0.1" + } + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", + "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", + "dev": true, + "requires": { + "circular-json": "0.3.1", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, "form-data": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=" + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "dev": true, + "requires": { + "samsam": "1.1.2" + } }, "formidable": { "version": "1.1.1", @@ -399,22 +1930,66 @@ "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", - "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=" + "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.1" + } }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "function-bind": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", + "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=", + "dev": true + }, "gauge": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz", - "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=" + "integrity": "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM=", + "requires": { + "ansi": "0.3.1", + "has-unicode": "2.0.1", + "lodash.pad": "4.5.1", + "lodash.padend": "4.6.1", + "lodash.padstart": "4.6.1" + } + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "1.0.2" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true }, "get-proxy": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-1.1.0.tgz", - "integrity": "sha1-iUhUSRvFkbDxR9euVw9cZ4tyVus=" + "integrity": "sha1-iUhUSRvFkbDxR9euVw9cZ4tyVus=", + "requires": { + "rc": "1.2.1" + } }, "get-stdin": { "version": "5.0.1", @@ -426,20 +2001,90 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=" + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true }, "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=" + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=" + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "requires": { + "create-error-class": "3.0.2", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-redirect": "1.0.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "lowercase-keys": "1.0.0", + "safe-buffer": "5.0.1", + "timed-out": "4.0.1", + "unzip-response": "2.0.1", + "url-parse-lax": "1.0.0" + } }, "graceful-fs": { "version": "4.1.11", @@ -454,12 +2099,18 @@ "graphlib": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.1.tgz", - "integrity": "sha1-QjUsUrovTQNctWbrkfc5X3bryVE=" + "integrity": "sha1-QjUsUrovTQNctWbrkfc5X3bryVE=", + "requires": { + "lodash": "4.17.4" + } }, "graphql": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.10.1.tgz", - "integrity": "sha1-dck8LOc661uuLu+1Vajp45w2An0=" + "integrity": "sha1-dck8LOc661uuLu+1Vajp45w2An0=", + "requires": { + "iterall": "1.1.1" + } }, "graphql-anywhere": { "version": "3.1.0", @@ -471,20 +2122,168 @@ "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.4.0.tgz", "integrity": "sha1-D+E3NI1Nsu+vKbUrpMHL+ErBOMs=" }, + "gray-matter": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz", + "integrity": "sha1-MELZrewqHe1qdwep7SOA+KF6Qw4=", + "dev": true, + "requires": { + "ansi-red": "0.1.1", + "coffee-script": "1.12.6", + "extend-shallow": "2.0.1", + "js-yaml": "3.8.4", + "toml": "2.3.2" + } + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "handlebars": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", + "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.8.1", + "is-my-json-valid": "2.16.0", + "pinkie-promise": "2.0.1" + } + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.0" + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=" + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + } }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", + "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", + "dev": true, + "requires": { + "whatwg-encoding": "1.0.1" + } + }, + "http-basic": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz", + "integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=", + "dev": true, + "requires": { + "caseless": "0.11.0", + "concat-stream": "1.6.0", + "http-response-object": "1.1.0" + } + }, + "http-response-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz", + "integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.1" + } + }, "https-proxy-agent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=" + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.8", + "extend": "3.0.1" + } }, "iconv-lite": { "version": "0.4.17", @@ -496,6 +2295,18 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" }, + "ignore": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", + "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=", + "dev": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -504,7 +2315,11 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=" + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } }, "inherits": { "version": "2.0.3", @@ -519,28 +2334,242 @@ "inquirer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz", - "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=" + "integrity": "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=", + "requires": { + "ansi-escapes": "1.4.0", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.1.0", + "external-editor": "1.1.1", + "figures": "1.7.0", + "lodash": "4.17.4", + "mute-stream": "0.0.6", + "pinkie-promise": "2.0.1", + "run-async": "2.3.0", + "rx": "4.1.0", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "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-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-ci": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz", + "integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=", + "dev": true, + "requires": { + "ci-info": "1.0.0" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } }, "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=" + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-local-path": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-local-path/-/is-local-path-0.1.6.tgz", + "integrity": "sha1-gV0USxTVac7L6tTVaTCX8Aqb9sU=", + "dev": true + }, + "is-my-json-valid": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } }, "is-natural-number": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=" }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.1" + } + }, + "is-resolvable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", + "dev": true, + "requires": { + "tryit": "1.0.3" + } + }, "is-retry-allowed": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", @@ -551,6 +2580,24 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", @@ -561,11 +2608,463 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "dev": true, + "requires": { + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "3.1.3", + "glob": "7.1.2", + "handlebars": "4.0.10", + "js-yaml": "3.8.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "2.0.0", + "which": "1.2.14", + "wordwrap": "1.0.0" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "istanbul-api": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.1.10.tgz", + "integrity": "sha1-8n5ecSXI3hP2qAZhr3j1EuVDmys=", + "dev": true, + "requires": { + "async": "1.5.2", + "fileset": "2.0.3", + "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-hook": "1.0.7", + "istanbul-lib-instrument": "1.7.3", + "istanbul-lib-report": "1.1.1", + "istanbul-lib-source-maps": "1.2.1", + "istanbul-reports": "1.1.1", + "js-yaml": "3.8.4", + "mkdirp": "0.5.1", + "once": "1.4.0" + } + }, + "istanbul-lib-coverage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", + "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz", + "integrity": "sha512-3U2HB9y1ZV9UmFlE12Fx+nPtFqIymzrqCksrXujm3NVbAZIJg/RfYgO1XiIa0mbmxTjWpVEVlkIZJ25xVIAfkQ==", + "dev": true, + "requires": { + "append-transform": "0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.3.tgz", + "integrity": "sha1-klsjkWPqvdaMxASPUsL6T4mez6c=", + "dev": true, + "requires": { + "babel-generator": "6.25.0", + "babel-template": "6.25.0", + "babel-traverse": "6.25.0", + "babel-types": "6.25.0", + "babylon": "6.17.4", + "istanbul-lib-coverage": "1.1.1", + "semver": "5.3.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-tvF+YmCmH4thnez6JFX06ujIA19WPa9YUiwjc1uALF2cv5dmE3It8b5I8Ob7FHJ70H9Y5yF+TDkVa/mcADuw1Q==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "1.1.1", + "mkdirp": "0.5.1", + "path-parse": "1.0.5", + "supports-color": "2.0.0" + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz", + "integrity": "sha512-mukVvSXCn9JQvdJl8wP/iPhqig0MRtuWuD4ZNKo6vB2Ik//AmhAKe3QnPN02dmkRe3lTudFk3rzoHhwU4hb94w==", + "dev": true, + "requires": { + "debug": "2.6.8", + "istanbul-lib-coverage": "1.1.1", + "mkdirp": "0.5.1", + "rimraf": "2.6.1", + "source-map": "0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-P8G873A0kW24XRlxHVGhMJBhQ8gWAec+dae7ZxOBzxT4w+a9ATSPvRVK3LB1RAJ9S8bg2tOyWHAGW40Zd2dKfw==", + "dev": true, + "requires": { + "handlebars": "4.0.10" + } + }, "iterall": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.1.tgz", "integrity": "sha1-9/CvEemgTsZCYmD1AZ2fzKTVAhQ=" }, + "jest-changed-files": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-17.0.2.tgz", + "integrity": "sha1-9WV3WHNplvWQpRuH5ck2nZBLp7c=", + "dev": true + }, + "jest-cli": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-18.1.0.tgz", + "integrity": "sha1-Xq027K1CCBfCybqiqnV09jJXs9Y=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "callsites": "2.0.0", + "chalk": "1.1.3", + "graceful-fs": "4.1.11", + "is-ci": "1.0.10", + "istanbul-api": "1.1.10", + "istanbul-lib-coverage": "1.1.1", + "istanbul-lib-instrument": "1.7.3", + "jest-changed-files": "17.0.2", + "jest-config": "18.1.0", + "jest-environment-jsdom": "18.1.0", + "jest-file-exists": "17.0.0", + "jest-haste-map": "18.1.0", + "jest-jasmine2": "18.1.0", + "jest-mock": "18.0.0", + "jest-resolve": "18.1.0", + "jest-resolve-dependencies": "18.1.0", + "jest-runtime": "18.1.0", + "jest-snapshot": "18.1.0", + "jest-util": "18.1.0", + "json-stable-stringify": "1.0.1", + "node-notifier": "4.6.1", + "sane": "1.4.1", + "strip-ansi": "3.0.1", + "throat": "3.2.0", + "which": "1.2.14", + "worker-farm": "1.4.1", + "yargs": "6.6.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "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.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "4.2.1" + } + } + } + }, + "jest-config": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-18.1.0.tgz", + "integrity": "sha1-YRF0Cm1Iqrhv9anmqwuYvZk7b/Q=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "jest-environment-jsdom": "18.1.0", + "jest-environment-node": "18.1.0", + "jest-jasmine2": "18.1.0", + "jest-mock": "18.0.0", + "jest-resolve": "18.1.0", + "jest-util": "18.1.0", + "json-stable-stringify": "1.0.1" + } + }, + "jest-diff": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-18.1.0.tgz", + "integrity": "sha1-T/eedN2YjBORlbNl3GXYf2BvSAM=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "diff": "3.3.0", + "jest-matcher-utils": "18.1.0", + "pretty-format": "18.1.0" + } + }, + "jest-environment-jsdom": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-18.1.0.tgz", + "integrity": "sha1-GLQvDE6iuunzbKs2ObHo+MOE4k4=", + "dev": true, + "requires": { + "jest-mock": "18.0.0", + "jest-util": "18.1.0", + "jsdom": "9.12.0" + } + }, + "jest-environment-node": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-18.1.0.tgz", + "integrity": "sha1-TWeXVyyN2pms9frmlutilFVHx3k=", + "dev": true, + "requires": { + "jest-mock": "18.0.0", + "jest-util": "18.1.0" + } + }, + "jest-file-exists": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/jest-file-exists/-/jest-file-exists-17.0.0.tgz", + "integrity": "sha1-f2Prc6HEOhP0Yb4mF2i0WvLN0Wk=", + "dev": true + }, + "jest-haste-map": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-18.1.0.tgz", + "integrity": "sha1-BoOcdLdwpAwaEGlohR340oHAg3U=", + "dev": true, + "requires": { + "fb-watchman": "1.9.2", + "graceful-fs": "4.1.11", + "micromatch": "2.3.11", + "sane": "1.4.1", + "worker-farm": "1.4.1" + } + }, + "jest-jasmine2": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-18.1.0.tgz", + "integrity": "sha1-CU4QTCwYlwh2bHcmO7Kuy1hgqAs=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jest-matcher-utils": "18.1.0", + "jest-matchers": "18.1.0", + "jest-snapshot": "18.1.0", + "jest-util": "18.1.0" + } + }, + "jest-matcher-utils": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-18.1.0.tgz", + "integrity": "sha1-GsRlGVXuKmDO8ef8yYzf13PA+TI=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "pretty-format": "18.1.0" + } + }, + "jest-matchers": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-18.1.0.tgz", + "integrity": "sha1-A0FIS/h6H9C6wKTSyJnit3o/Hq0=", + "dev": true, + "requires": { + "jest-diff": "18.1.0", + "jest-matcher-utils": "18.1.0", + "jest-util": "18.1.0", + "pretty-format": "18.1.0" + } + }, + "jest-mock": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-18.0.0.tgz", + "integrity": "sha1-XCSIRuoz+lWLUm9TEqtKZ2XkibM=", + "dev": true + }, + "jest-resolve": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-18.1.0.tgz", + "integrity": "sha1-aACsy1NmWMkGzV4p3kErGrmsJJs=", + "dev": true, + "requires": { + "browser-resolve": "1.11.2", + "jest-file-exists": "17.0.0", + "jest-haste-map": "18.1.0", + "resolve": "1.3.3" + } + }, + "jest-resolve-dependencies": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-18.1.0.tgz", + "integrity": "sha1-gTT7XK9Zye2EL+AVKrAcUnEfG7s=", + "dev": true, + "requires": { + "jest-file-exists": "17.0.0", + "jest-resolve": "18.1.0" + } + }, + "jest-runtime": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-18.1.0.tgz", + "integrity": "sha1-Or/WhxdbIfw7haK4BkOZ6ZeFmSI=", + "dev": true, + "requires": { + "babel-core": "6.25.0", + "babel-jest": "18.0.0", + "babel-plugin-istanbul": "3.1.2", + "chalk": "1.1.3", + "graceful-fs": "4.1.11", + "jest-config": "18.1.0", + "jest-file-exists": "17.0.0", + "jest-haste-map": "18.1.0", + "jest-mock": "18.0.0", + "jest-resolve": "18.1.0", + "jest-snapshot": "18.1.0", + "jest-util": "18.1.0", + "json-stable-stringify": "1.0.1", + "micromatch": "2.3.11", + "yargs": "6.6.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "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.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "4.2.1" + } + } + } + }, + "jest-snapshot": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-18.1.0.tgz", + "integrity": "sha1-VbltLuY5ybznb4fyo/1Atxx6WRY=", + "dev": true, + "requires": { + "jest-diff": "18.1.0", + "jest-file-exists": "17.0.0", + "jest-matcher-utils": "18.1.0", + "jest-util": "18.1.0", + "natural-compare": "1.4.0", + "pretty-format": "18.1.0" + } + }, + "jest-util": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-18.1.0.tgz", + "integrity": "sha1-OpnDIRSrF/hL4JQ4JScAbm1L/Go=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "diff": "3.3.0", + "graceful-fs": "4.1.11", + "jest-file-exists": "17.0.0", + "jest-mock": "18.0.0", + "mkdirp": "0.5.1" + } + }, "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", @@ -579,44 +3078,307 @@ "js-yaml": { "version": "3.8.4", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz", - "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=" + "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=", + "requires": { + "argparse": "1.0.9", + "esprima": "3.1.3" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsdom": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", + "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=", + "dev": true, + "requires": { + "abab": "1.0.3", + "acorn": "4.0.13", + "acorn-globals": "3.1.0", + "array-equal": "1.0.0", + "content-type-parser": "1.0.1", + "cssom": "0.3.2", + "cssstyle": "0.2.37", + "escodegen": "1.8.1", + "html-encoding-sniffer": "1.0.1", + "nwmatcher": "1.4.1", + "parse5": "1.5.1", + "request": "2.79.0", + "sax": "1.2.1", + "symbol-tree": "3.2.2", + "tough-cookie": "2.3.2", + "webidl-conversions": "4.0.1", + "whatwg-encoding": "1.0.1", + "whatwg-url": "4.8.0", + "xml-name-validator": "2.0.1" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true }, "json-refs": { "version": "2.1.7", "resolved": "https://registry.npmjs.org/json-refs/-/json-refs-2.1.7.tgz", "integrity": "sha1-uesB/in16j6Sh48VrqEK04taz4k=", + "requires": { + "commander": "2.9.0", + "graphlib": "2.1.1", + "js-yaml": "3.8.4", + "native-promise-only": "0.8.1", + "path-loader": "1.0.2", + "slash": "1.0.0", + "uri-js": "3.0.2" + }, "dependencies": { "commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=" + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "requires": { + "graceful-readlink": "1.0.1" + } } } }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "0.0.0" + } + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=" + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", + "dev": true + }, + "jszip": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.3.tgz", + "integrity": "sha1-ipIEA7KxZRwPwSa+kBktkICVfDc=", + "dev": true, + "requires": { + "core-js": "2.3.0", + "es6-promise": "3.0.2", + "lie": "3.1.1", + "pako": "1.0.5", + "readable-stream": "2.2.11" + }, + "dependencies": { + "core-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", + "dev": true + } + } }, "jwt-decode": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", "integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk=" }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + }, "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=" + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true }, "lazystream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=" + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "2.2.11" + } + }, + "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" + } + }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "dev": true, + "requires": { + "immediate": "3.0.6" + } + }, + "list-item": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz", + "integrity": "sha1-DGXQDih8tmPMs8s4Sad+iewmilY=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "extend-shallow": "2.0.1", + "is-number": "2.1.0", + "repeat-string": "1.6.1" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } }, "lodash": { "version": "4.17.4", @@ -628,11 +3390,157 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz", "integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc=" }, + "lodash._arraycopy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", + "integrity": "sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=", + "dev": true + }, + "lodash._arrayeach": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", + "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._baseclone": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", + "integrity": "sha1-MDUZv2OT/n5C802LYw73eU41Qrc=", + "dev": true, + "requires": { + "lodash._arraycopy": "3.0.0", + "lodash._arrayeach": "3.0.0", + "lodash._baseassign": "3.2.0", + "lodash._basefor": "3.0.3", + "lodash.isarray": "3.0.4", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._basefor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", + "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=", + "dev": true + }, + "lodash._bindcallback": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.clonedeep": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", + "integrity": "sha1-oKHkDYKl6on/WxR7hETtY9koJ9s=", + "dev": true, + "requires": { + "lodash._baseclone": "3.3.0", + "lodash._bindcallback": "3.0.1" + } + }, + "lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, "lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" }, + "lodash.endswith": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.endswith/-/lodash.endswith-4.2.1.tgz", + "integrity": "sha1-/tWawXOO0+I27dcGTsRWRIs3vAk=", + "dev": true + }, + "lodash.find": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", + "integrity": "sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=", + "dev": true + }, + "lodash.findindex": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.findindex/-/lodash.findindex-4.6.0.tgz", + "integrity": "sha1-oyRd7mH7m24GJLU1ElYku2nBEQY=", + "dev": true + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, "lodash.pad": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz", @@ -653,10 +3561,31 @@ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, + "log-driver": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", + "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=", + "dev": true + }, + "lolex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=" + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "requires": { + "js-tokens": "3.0.1" + } }, "lowercase-keys": { "version": "1.0.0", @@ -671,13 +3600,141 @@ "make-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz", - "integrity": "sha1-l6ARdR6R3YfPre9Ygy67BJNt6Xg=" + "integrity": "sha1-l6ARdR6R3YfPre9Ygy67BJNt6Xg=", + "requires": { + "pify": "2.3.0" + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.4" + } + }, + "markdown-link": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/markdown-link/-/markdown-link-0.1.1.tgz", + "integrity": "sha1-MsXGUZmmRXMWMi0eQinRNAfIx88=", + "dev": true + }, + "markdown-magic": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/markdown-magic/-/markdown-magic-0.1.17.tgz", + "integrity": "sha1-lj/jsNvoIF5ycJRJpErS9NsR/24=", + "dev": true, + "requires": { + "commander": "2.8.1", + "deepmerge": "1.5.0", + "find-up": "2.1.0", + "fs-extra": "0.26.7", + "globby": "6.1.0", + "is-local-path": "0.1.6", + "markdown-toc": "1.1.0", + "sync-request": "3.0.1" + }, + "dependencies": { + "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" + } + } + } + }, + "markdown-toc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/markdown-toc/-/markdown-toc-1.1.0.tgz", + "integrity": "sha1-GORyN9iVSelEcSHmniyoU8otdSo=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "diacritics-map": "0.1.0", + "gray-matter": "2.1.1", + "lazy-cache": "2.0.2", + "list-item": "1.1.1", + "markdown-link": "0.1.1", + "minimist": "1.2.0", + "mixin-deep": "1.2.0", + "object.pick": "1.2.0", + "remarkable": "1.7.1", + "repeat-string": "1.6.1", + "strip-color": "0.1.0" + }, + "dependencies": { + "lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", + "dev": true, + "requires": { + "set-getter": "0.1.0" + } + } + } + }, + "marked": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz", + "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc=", + "dev": true + }, + "marked-terminal": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-1.7.0.tgz", + "integrity": "sha1-yMRgiBx3LHYEtkNnAH7l938SWQQ=", + "dev": true, + "requires": { + "cardinal": "1.0.0", + "chalk": "1.1.3", + "cli-table": "0.3.1", + "lodash.assign": "4.2.0", + "node-emoji": "1.5.1" + } + }, + "merge": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", + "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", + "dev": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.3" + } + }, "mime": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.6.tgz", @@ -691,22 +3748,41 @@ "mime-types": { "version": "2.1.15", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", - "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=" + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "requires": { + "mime-db": "1.27.0" + } }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=" + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "1.1.7" + } }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, + "mixin-deep": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.2.0.tgz", + "integrity": "sha1-0CuMb4ttS49ZgtP9AJxJGYUcP+I=", + "dev": true, + "requires": { + "for-in": "1.0.2", + "is-extendable": "0.1.1" + } + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, "dependencies": { "minimist": { "version": "0.0.8", @@ -715,6 +3791,54 @@ } } }, + "mocha": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.4.2.tgz", + "integrity": "sha1-0O9NMyEm2/GNDWQMmzgt1IvpdZQ=", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.8.1", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.9.2", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + } + } + }, + "mocha-lcov-reporter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mocha-lcov-reporter/-/mocha-lcov-reporter-1.3.0.tgz", + "integrity": "sha1-Rpve9PivyaEWBW8HnfYYLQr7A4Q=", + "dev": true + }, + "mock-require": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-1.3.0.tgz", + "integrity": "sha1-gmFElS5QR2L45pJKqPY5Rl0deiQ=", + "dev": true, + "requires": { + "caller-id": "0.1.0" + } + }, + "module-not-found-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", + "integrity": "sha1-z4tP9PKWQGdNbN0CsOO8UjwrvcA=", + "dev": true + }, "moment": { "version": "2.18.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", @@ -735,35 +3859,155 @@ "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-emoji": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.5.1.tgz", + "integrity": "sha1-/ZGOQSdpv4xEgFEjgjOECyr/FqE=", + "dev": true, + "requires": { + "string.prototype.codepointat": "0.2.0" + } + }, "node-fetch": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", - "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==" + "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==", + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-notifier": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-4.6.1.tgz", + "integrity": "sha1-BW0UJE89zBzq3+aK+c/wxUc6M/M=", + "dev": true, + "requires": { + "cli-usage": "0.1.4", + "growly": "1.3.0", + "lodash.clonedeep": "3.0.2", + "minimist": "1.2.0", + "semver": "5.3.0", + "shellwords": "0.1.0", + "which": "1.2.14" + } + }, + "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.0.9" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.3.0", + "validate-npm-package-license": "3.0.1" + } }, "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=" + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "1.0.2" + } }, "npmlog": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz", - "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=" + "integrity": "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI=", + "requires": { + "ansi": "0.3.1", + "are-we-there-yet": "1.1.4", + "gauge": "1.2.7" + } }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, + "nwmatcher": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.1.tgz", + "integrity": "sha1-eumwew6oBNt+JfBctf5Al9TklJ8=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object.assign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "function-bind": "1.1.0", + "object-keys": "1.0.11" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "object.pick": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.2.0.tgz", + "integrity": "sha1-tTkr7peC2m2ft9avr1OXefEjTCs=", + "dev": true, + "requires": { + "isobject": "2.1.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=" + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } }, "onetime": { "version": "1.1.0", @@ -773,7 +4017,57 @@ "opn": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", - "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==" + "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", + "requires": { + "is-wsl": "1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "1.2.0", + "wordwrap": "0.0.3" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "1.0.0" + } }, "os-shim": { "version": "0.1.3", @@ -785,15 +4079,99 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.1.0" + } + }, + "pako": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.5.tgz", + "integrity": "sha1-0iBd/ludqK95fnwWPbTR+E5GALw=", + "dev": true + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "parse5": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", + "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, "path-loader": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-loader/-/path-loader-1.0.2.tgz", - "integrity": "sha1-zVxz5+OakQEb4UjWv92KhbuTHvk=" + "integrity": "sha1-zVxz5+OakQEb4UjWv92KhbuTHvk=", + "requires": { + "native-promise-only": "0.8.1", + "superagent": "3.5.2" + } + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } }, "pend": { "version": "1.2.0", @@ -813,18 +4191,112 @@ "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=" + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-format": { + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-18.1.0.tgz", + "integrity": "sha1-+2Wob3p/kZSWPu6RhlwbzxA54oQ=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1" + } + }, + "private": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", + "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=", + "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": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "requires": { + "asap": "2.0.5" + } + }, + "proxyquire": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-1.8.0.tgz", + "integrity": "sha1-AtUUpb7ZhvBMuyCTrxZ0FTX3ntw=", + "dev": true, + "requires": { + "fill-keys": "1.0.2", + "module-not-found-error": "1.0.1", + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "prr": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "dev": true + }, "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", @@ -840,10 +4312,58 @@ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, "raven": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/raven/-/raven-1.2.1.tgz", "integrity": "sha1-lJwTTbAooZC3u/j3kKrlQbfAIL0=", + "requires": { + "cookie": "0.3.1", + "json-stringify-safe": "5.0.1", + "lsmod": "1.0.0", + "stack-trace": "0.0.9", + "uuid": "3.0.0" + }, "dependencies": { "uuid": { "version": "3.0.0", @@ -855,42 +4375,225 @@ "rc": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", - "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=" + "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=", + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } }, "readable-stream": { "version": "2.2.11", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.11.tgz", - "integrity": "sha512-h+8+r3MKEhkiVrwdKL8aWs1oc1VvBu33ueshOvS26RsZQ3Amhx/oO3TKe4lApSV9ueY6as8EAh7mtuFjdlhg9Q==" + "integrity": "sha512-h+8+r3MKEhkiVrwdKL8aWs1oc1VvBu33ueshOvS26RsZQ3Amhx/oO3TKe4lApSV9ueY6as8EAh7mtuFjdlhg9Q==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.0.1", + "string_decoder": "1.0.2", + "util-deprecate": "1.0.2" + } + }, + "redeyed": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz", + "integrity": "sha1-6WwZO0DAgWsArshCaY5hGF5VSYo=", + "dev": true, + "requires": { + "esprima": "3.1.3" + } }, "redux": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.0.tgz", - "integrity": "sha512-GHjaOkEQtQnnuLoYPFkRKHIqs1i1tdTlisu/xUHfk2juzCobSy4STxs4Lz5bPkc07Owb6BeGKx/r76c9IVTkOw==" + "integrity": "sha512-GHjaOkEQtQnnuLoYPFkRKHIqs1i1tdTlisu/xUHfk2juzCobSy4STxs4Lz5bPkc07Owb6BeGKx/r76c9IVTkOw==", + "requires": { + "lodash": "4.17.4", + "lodash-es": "4.17.4", + "loose-envify": "1.3.1", + "symbol-observable": "1.0.4" + } + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + }, + "regex-cache": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", + "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3", + "is-primitive": "2.0.0" + } + }, + "remarkable": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.1.tgz", + "integrity": "sha1-qspJchALZqZCpjoQIcpLrBvjv/Y=", + "dev": true, + "requires": { + "argparse": "1.0.9", + "autolinker": "0.15.3" + } }, "remove-trailing-separator": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=" }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, "replaceall": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/replaceall/-/replaceall-0.1.6.tgz", "integrity": "sha1-gdgax663LX9cSUKt8ml6MiBojY4=" }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "qs": "6.4.0", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.4.3", + "uuid": "2.0.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "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 + }, + "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.1" + } + }, + "resolve": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", + "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "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 + }, "restore-cursor": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=" + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4" + } }, "rimraf": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", - "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=" + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "requires": { + "glob": "7.1.2" + } }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=" + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "2.1.0" + } }, "rx": { "version": "4.1.0", @@ -902,6 +4605,26 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" }, + "samsam": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", + "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", + "dev": true + }, + "sane": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sane/-/sane-1.4.1.tgz", + "integrity": "sha1-iPdj10BA9fDCVrYWPbOZvxEKxxU=", + "dev": true, + "requires": { + "exec-sh": "0.2.0", + "fb-watchman": "1.9.2", + "minimatch": "3.0.4", + "minimist": "1.2.0", + "walker": "1.0.7", + "watch": "0.10.0" + } + }, "sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", @@ -910,7 +4633,10 @@ "seek-bzip": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", - "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=" + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "requires": { + "commander": "2.8.1" + } }, "semver": { "version": "5.3.0", @@ -922,31 +4648,167 @@ "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-1.0.0.tgz", "integrity": "sha1-kqSWkGX5xwxpR1PVUkj8aPj2Usk=" }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-getter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", + "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", + "dev": true, + "requires": { + "to-object-path": "0.3.0" + } + }, "shelljs": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz", "integrity": "sha1-7GIRvtGSBEIIj+D3Cyg3Iy7SyKg=" }, + "shellwords": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz", + "integrity": "sha1-Zq/Ue2oSky2Qccv9mKUueFzQuhQ=", + "dev": true + }, + "sinon": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", + "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", + "dev": true, + "requires": { + "formatio": "1.1.1", + "lolex": "1.3.2", + "samsam": "1.1.2", + "util": "0.10.3" + } + }, + "sinon-bluebird": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/sinon-bluebird/-/sinon-bluebird-3.1.0.tgz", + "integrity": "sha1-+SaA+lRtVTpPX2LekEJetdxHhB0=", + "dev": true + }, + "sinon-chai": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.11.0.tgz", + "integrity": "sha512-3kbzpr2q8N+M4CWkcym349ifwkXorsbw2YyVpEIvB3AKC/ebrLHXj3DySt8epKGA49zJBSgn1OvWHZ+O+aR0dA==", + "dev": true + }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, "slide": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "source-map-support": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", + "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", + "dev": true, + "requires": { + "source-map": "0.5.6" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + } + } + }, "spawn-sync": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=" + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "requires": { + "concat-stream": "1.6.0", + "os-shim": "0.1.3" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, "stack-trace": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", @@ -955,22 +4817,60 @@ "string_decoder": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.2.tgz", - "integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=" + "integrity": "sha1-sp4fThEl+pehA4K4pTNze3SR4Xk=", + "requires": { + "safe-buffer": "5.0.1" + } }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=" + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string.prototype.codepointat": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.0.tgz", + "integrity": "sha1-aybpvTr8qnvjtCabUm3huCAArHg=", + "dev": true + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=" + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-color": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", + "integrity": "sha1-EG9l09PmotlAHKwOsM6LinArT3s=", + "dev": true }, "strip-dirs": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.0.0.tgz", - "integrity": "sha1-YQzbKSggDaAAT0HcuQ/JXNkZoLY=" + "integrity": "sha1-YQzbKSggDaAAT0HcuQ/JXNkZoLY=", + "requires": { + "is-natural-number": "4.0.1" + } }, "strip-json-comments": { "version": "2.0.1", @@ -980,12 +4880,27 @@ "strip-outer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.0.tgz", - "integrity": "sha1-qsC6YNLpDF1PJ1/Yhp/ZotMQ/7g=" + "integrity": "sha1-qsC6YNLpDF1PJ1/Yhp/ZotMQ/7g=", + "requires": { + "escape-string-regexp": "1.0.5" + } }, "superagent": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.5.2.tgz", - "integrity": "sha1-M2GjlxVnUEw1EGOr6q4PqiPb8/g=" + "integrity": "sha1-M2GjlxVnUEw1EGOr6q4PqiPb8/g=", + "requires": { + "component-emitter": "1.2.1", + "cookiejar": "2.1.1", + "debug": "2.6.8", + "extend": "3.0.1", + "form-data": "2.1.4", + "formidable": "1.1.1", + "methods": "1.1.2", + "mime": "1.3.6", + "qs": "6.4.0", + "readable-stream": "2.2.11" + } }, "supports-color": { "version": "2.0.0", @@ -997,15 +4912,101 @@ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=" }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "sync-request": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz", + "integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "http-response-object": "1.1.0", + "then-request": "2.2.0" + } + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.4", + "slice-ansi": "0.0.4", + "string-width": "1.0.2" + } + }, "tabtab": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/tabtab/-/tabtab-2.2.2.tgz", - "integrity": "sha1-egR/FDsBC0y9MfhX6ClhUSy/ThQ=" + "integrity": "sha1-egR/FDsBC0y9MfhX6ClhUSy/ThQ=", + "requires": { + "debug": "2.6.8", + "inquirer": "1.2.3", + "lodash.difference": "4.5.0", + "lodash.uniq": "4.5.0", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "npmlog": "2.0.4", + "object-assign": "4.1.1" + } }, "tar-stream": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz", - "integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=" + "integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=", + "requires": { + "bl": "1.2.1", + "end-of-stream": "1.4.0", + "readable-stream": "2.2.11", + "xtend": "4.0.1" + } + }, + "test-exclude": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-3.3.0.tgz", + "integrity": "sha1-ehfKEjmYjJg2ewYhRW27fUvDiXc=", + "dev": true, + "requires": { + "arrify": "1.0.1", + "micromatch": "2.3.11", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "then-request": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz", + "integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=", + "dev": true, + "requires": { + "caseless": "0.11.0", + "concat-stream": "1.6.0", + "http-basic": "2.5.1", + "http-response-object": "1.1.0", + "promise": "7.3.1", + "qs": "6.4.0" + } + }, + "throat": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-3.2.0.tgz", + "integrity": "sha512-/EY8VpvlqJ+sFtLPeOgc8Pl7kQVOWv0woD87KTXVHPIAE842FGT+rokxIhe8xIUP1cfgrkt0as0vDLjDiMtr8w==", + "dev": true }, "through": { "version": "2.3.8", @@ -1020,27 +5021,141 @@ "tmp": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz", - "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=" + "integrity": "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=", + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "toml": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.2.tgz", + "integrity": "sha1-Xt7VykKIeSSUn9BusOlVZWAB6DQ=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "dev": true, + "requires": { + "punycode": "1.3.2" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true }, "trim-repeated": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", - "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=" + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tryit": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "dev": true }, "tunnel-agent": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=" }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "0.5.6", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true, + "optional": true + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, "unbzip2-stream": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.4.tgz", "integrity": "sha1-jITITVtMwo/B+fV3IDu9PLhgoWo=", + "requires": { + "buffer": "3.6.0", + "through": "2.3.8" + }, "dependencies": { "base64-js": { "version": "0.0.8", @@ -1050,7 +5165,12 @@ "buffer": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", - "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=" + "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "requires": { + "base64-js": "0.0.8", + "ieee754": "1.1.8", + "isarray": "1.0.0" + } } } }, @@ -1063,6 +5183,9 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", + "requires": { + "punycode": "2.1.0" + }, "dependencies": { "punycode": { "version": "2.1.0", @@ -1074,12 +5197,37 @@ "url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=" + "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=" + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "requires": { + "prepend-http": "1.0.4" + } + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } }, "util-deprecate": { "version": "1.0.2", @@ -1091,50 +5239,238 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "dev": true, + "requires": { + "extsprintf": "1.0.2" + } + }, "walkdir": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz", "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=" }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.11" + } + }, + "watch": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz", + "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw=", + "dev": true + }, + "webidl-conversions": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.1.tgz", + "integrity": "sha1-gBWherg+fhsxFjhIas6B2mziBqA=", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", + "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", + "dev": true, + "requires": { + "iconv-lite": "0.4.17" + } + }, "whatwg-fetch": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=" }, + "whatwg-url": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", + "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", + "dev": true, + "requires": { + "tr46": "0.0.3", + "webidl-conversions": "3.0.1" + }, + "dependencies": { + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + } + } + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "worker-farm": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.4.1.tgz", + "integrity": "sha512-tgFAtgOYLPutkAyzgpS6VJFL5HY+0ui1Tvua+fITgz8ByaJTMFGtazR6xxQfwfiAcbwE+2fLG/K49wc2TfwCNw==", + "dev": true, + "requires": { + "errno": "0.1.4", + "xtend": "4.0.1" + } + }, + "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.2", + "strip-ansi": "3.0.1" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "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" + } + }, "write-file-atomic": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.1.0.tgz", - "integrity": "sha1-F2n0tVHu3OQZ8FBd6uLiZ2NULTc=" + "integrity": "sha1-F2n0tVHu3OQZ8FBd6uLiZ2NULTc=", + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, + "xml-name-validator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", + "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", + "dev": true }, "xml2js": { "version": "0.4.17", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", - "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=" + "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", + "requires": { + "sax": "1.2.1", + "xmlbuilder": "4.2.1" + } }, "xmlbuilder": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", - "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=" + "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", + "requires": { + "lodash": "4.17.4" + } }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + } + } + }, "yauzl": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.8.0.tgz", - "integrity": "sha1-eUUK/yKyqcWkHvVOAtuQfM+/nuI=" + "integrity": "sha1-eUUK/yKyqcWkHvVOAtuQfM+/nuI=", + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.0.1" + } }, "zip-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.1.1.tgz", - "integrity": "sha1-Uha0i7tNJlH2TVxubwnrSnOZ1Vc=" + "integrity": "sha1-Uha0i7tNJlH2TVxubwnrSnOZ1Vc=", + "requires": { + "archiver-utils": "1.3.0", + "compress-commons": "1.2.0", + "lodash": "4.17.4", + "readable-stream": "2.2.11" + } } } } diff --git a/package.json b/package.json index cbe4f0e77..4dcbd8e00 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "serverless", - "version": "1.16.1", + "version": "1.17.0", "engines": { "node": ">=4.0" },