From 57f1b05fbd518878d43202ffc82c24171ac42aeb Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Tue, 26 Nov 2019 14:29:27 +0100 Subject: [PATCH 01/20] feat: adds JSON Schema Draft 6/7 support --- lib/errors.js | 4 +- lib/validators/json-schema-legacy.js | 182 ++++++++++ lib/validators/json-schema-next.js | 129 +++++++ lib/validators/json-schema.js | 328 +----------------- package-lock.json | 14 +- package.json | 1 + test/fixtures/invalid-schema-v6.json | 15 + test/fixtures/invalid-schema-v7.json | 12 + test/fixtures/valid-schema-v4.json | 30 +- test/fixtures/valid-schema-v6.json | 11 + test/fixtures/valid-schema-v7.json | 12 + test/unit/validators/json-ajv.test.js | 79 +++++ .../validators/json-schema-legacy.test.js | 188 ++++++++++ test/unit/validators/json-schema-next.test.js | 206 +++++++++++ test/unit/validators/json-schema.test.js | 2 +- 15 files changed, 868 insertions(+), 345 deletions(-) create mode 100644 lib/validators/json-schema-legacy.js create mode 100644 lib/validators/json-schema-next.js create mode 100644 test/fixtures/invalid-schema-v6.json create mode 100644 test/fixtures/invalid-schema-v7.json create mode 100644 test/fixtures/valid-schema-v6.json create mode 100644 test/fixtures/valid-schema-v7.json create mode 100644 test/unit/validators/json-ajv.test.js create mode 100644 test/unit/validators/json-schema-legacy.test.js create mode 100644 test/unit/validators/json-schema-next.test.js diff --git a/lib/errors.js b/lib/errors.js index b6863dcf..63221ed0 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -7,6 +7,7 @@ class UnknownValidatorError extends Error {} class NotValidatableError extends Error {} class NotEnoughDataError extends Error {} class JsonSchemaNotValid extends Error {} +class JsonSchemaNotSupported extends Error {} module.exports = { DataNotJsonParsableError, @@ -18,4 +19,5 @@ module.exports = { NotValidatableError, NotEnoughDataError, JsonSchemaNotValid, -} + JsonSchemaNotSupported +}; diff --git a/lib/validators/json-schema-legacy.js b/lib/validators/json-schema-legacy.js new file mode 100644 index 00000000..51c36d2e --- /dev/null +++ b/lib/validators/json-schema-legacy.js @@ -0,0 +1,182 @@ +const amanda = require('amanda'); +const tv4 = require('tv4'); +const jsonPointer = require('json-pointer'); + +const { JsonSchemaValidator, META_SCHEMA } = require('./json-schema-next'); +const { ValidationErrors } = require('./validation-errors'); + +/** + * Returns a proper article for a given string. + * @param {string} str + * @returns {string} + */ +function getArticle(str) { + return ['a', 'e', 'i', 'o', 'u'].includes(str.toLowerCase()) ? 'an' : 'a'; +} + +const jsonSchemaOptions = { + singleError: false, + messages: { + minLength: (prop, val, validator) => + `The ${prop} property must be at least ${validator} characters long (currently ${val.length} characters long).`, + maxLength: (prop, val, validator) => + `The ${prop} property must not exceed ${validator} characters (currently${val.length} characters long).`, + length: (prop, val, validator) => + `The ${prop} property must be exactly ${validator} characters long (currently ${val.length} characters long).`, + format: (prop, val, validator) => + `The ${prop} property must be ${getArticle( + validator[0] + )} ${validator} (current value is ${JSON.stringify(val)}).`, + type: (prop, val, validator) => + `The ${prop} property must be ${getArticle( + validator[0] + )} ${validator} (current value is ${JSON.stringify(val)})."`, + except: (prop, val) => `The ${prop} property must not be ${val}.`, + minimum: (prop, val, validator) => + `The minimum value of the ${prop} must be ${validator} (current value is ${JSON.stringify( + val + )}).`, + maximum: (prop, val, validator) => + `The maximum value of the ${prop} must be ${validator} (current value is ${JSON.stringify( + val + )}).`, + pattern: (prop, val, validator) => + `The ${prop} value (${val}) does not match the ${validator} pattern.`, + maxItems: (prop, val, validator) => + `The ${prop} property must not contain more than ${validator} items (currently contains ${val.length} items).`, + minItems: (prop, val, validator) => + `The ${prop} property must contain at least ${validator} items (currently contains ${val.length} items).`, + divisibleBy: (prop, val, validator) => + `The ${prop} property is not divisible by ${validator} (current value is ${JSON.stringify( + val + )}).`, + uniqueItems: (prop) => `All items in the ${prop} property must be unique.` + } +}; + +class JsonSchemaLegacy extends JsonSchemaValidator { + validateSchema() { + const { jsonSchema, jsonMetaSchema } = this; + const metaSchema = jsonMetaSchema || META_SCHEMA.v3; + + tv4.reset(); + tv4.addSchema('', metaSchema); + tv4.addSchema(metaSchema.$schema, metaSchema); + const validationResult = tv4.validateResult(jsonSchema, metaSchema); + + return validationResult.valid; + } + + validate(data) { + switch (this.jsonSchemaVersion) { + case 'v3': + return this.validateUsingAmanda(data); + case 'v4': + return this.validateUsingTV4(data); + default: + throw new Error( + 'Attempted to use JsonSchemaLegacy on non-legacy JSON Schema!' + ); + } + } + + validateUsingAmanda(data) { + let errors = { + length: 0, + errorMessages: {} + }; + + try { + amanda.validate(data, this.jsonSchema, jsonSchemaOptions, (error) => { + if (error && error.length > 0) { + for (let i = 0; i < error.length; i++) { + if (error[i].property === '') { + error[i].property = []; + } + } + + errors = new ValidationErrors(error); + } + }); + } catch (error) { + errors = new ValidationErrors({ + '0': { + property: [], + attributeValue: true, + message: `Validator internal error: ${error.message}`, + validatorName: 'error' + }, + length: 1, + errorMessages: {} + }); + } + + return this.toGavelResult(errors); + } + + validateUsingTV4(data) { + const result = tv4.validateMultiple(data, this.jsonSchema); + const validationErrors = result.errors.concat(result.missing); + + const amandaCompatibleError = { + length: validationErrors.length, + errorMessages: {} + }; + + for (let index = 0; index < validationErrors.length; index++) { + const validationError = validationErrors[index]; + let error; + + if (validationError instanceof Error) { + error = validationError; + } else { + error = new Error('Missing schema'); + error.params = { key: validationError }; + error.dataPath = ''; + } + + const pathArray = jsonPointer + .parse(error.dataPath) + .concat(error.params.key || []); + const pointer = jsonPointer.compile(pathArray); + + amandaCompatibleError[index] = { + message: `At '${pointer}' ${error.message}`, + property: pathArray, + attributeValue: true, + validatorName: 'error' + }; + } + + const errors = new ValidationErrors(amandaCompatibleError); + return this.toGavelResult(errors); + } + + /** + * Converts Amanda-like validation result to the + * unified Gavel public validation result. + */ + toGavelResult(amandaLikeResult) { + const results = Array.from( + { length: amandaLikeResult.length }, + (_, index) => { + const item = amandaLikeResult[index]; + const { property, message } = item; + const pathArray = [].concat(property).filter(Boolean); + const pointer = jsonPointer.compile(pathArray); + + return { + message, + location: { + pointer, + property + } + }; + } + ); + + return results; + } +} + +module.exports = { JsonSchemaLegacy }; diff --git a/lib/validators/json-schema-next.js b/lib/validators/json-schema-next.js new file mode 100644 index 00000000..5ade9bbe --- /dev/null +++ b/lib/validators/json-schema-next.js @@ -0,0 +1,129 @@ +const Ajv = require('ajv'); +const metaSchemaV6 = require('ajv/lib/refs/json-schema-draft-06.json'); +const metaSchemaV7 = require('ajv/lib/refs/json-schema-draft-07.json'); + +const metaSchemaV4 = require('../meta-schema-v4'); +const metaSchemaV3 = require('../meta-schema-v3'); +const errors = require('../errors'); + +const SCHEMA_VERSIONS = { + v3: 'http://json-schema.org/draft-03/schema', + v4: 'http://json-schema.org/draft-04/schema', + v6: 'http://json-schema.org/draft-06/schema', + v7: 'http://json-schema.org/draft-07/schema' +}; + +const META_SCHEMA = { + v3: metaSchemaV3, + v4: metaSchemaV4, + v6: metaSchemaV6, + v7: metaSchemaV7 +}; + +/** + * Returns a JSON Schema Draft version of the given JSON Schema. + */ +const getSchemaVersion = (jsonSchema) => { + const jsonSchemaVersion = Object.keys(SCHEMA_VERSIONS).find((version) => { + const jsonSchemaAnnotation = SCHEMA_VERSIONS[version]; + return ( + jsonSchema.$schema && jsonSchema.$schema.includes(jsonSchemaAnnotation) + ); + }); + + if (jsonSchemaVersion == null) { + throw new errors.JsonSchemaNotSupported( + `Provided JSON Schema version is missing, or not supported. Please provide a JSON Schema Draft ${Object.keys( + SCHEMA_VERSIONS + ).join('/')}.` + ); + } + + return jsonSchemaVersion; +}; + +class JsonSchemaValidator { + constructor(jsonSchema) { + this.jsonSchema = jsonSchema; + this.jsonSchemaVersion = getSchemaVersion(jsonSchema); + this.jsonMetaSchema = this.getMetaSchema(); + + const isSchemaValid = this.validateSchema(); + if (!isSchemaValid) { + throw new errors.JsonSchemaNotValid( + `Provided JSON Schema is not a valid JSON Schema Draft ${this.jsonSchemaVersion}.` + ); + } + } + + /** + * Returns a meta schema for the provided JSON Schema. + */ + getMetaSchema() { + return META_SCHEMA[this.jsonSchemaVersion]; + } + + /** + * Validates the schema against its version specification. + * @return {boolean} + */ + validateSchema() { + const { jsonSchemaVersion, jsonSchema } = this; + let isSchemaValid = true; + + // use AJV to validate modern schema (6/7) + const ajv = new Ajv(); + + const metaSchema = META_SCHEMA[jsonSchemaVersion]; + ajv.addMetaSchema(metaSchema, 'meta'); + + isSchemaValid = ajv.validateSchema(jsonSchema); + + // Clean up the added meta schema + ajv.removeSchema('meta'); + + return isSchemaValid; + } + + /** + * Validates the given data. + */ + validate(data) { + const ajv = new Ajv({ + // Disable adding JSON Schema Draft 7 meta schema by default. + // Allows to always add a meta schema depending on the schema version. + meta: false, + // No need to validate schema again, already validated + // in "validateSchema()" method. + validateSchema: false, + // Make AJV point to the property in "error.dataPath", + // so it could be used as a complete pointer. + // errorDataPath: 'property', + jsonPointers: true + }); + + ajv.validate(this.jsonSchema, data); + + // Convert AJV validation errors to the Gavel public validation errors. + return (ajv.errors || []).map((ajvError) => { + const errorMessage = ajv.errorsText([ajvError]); + const { dataPath: pointer } = ajvError; + const property = + ajvError.params.missingProperty || pointer.split('/').filter(Boolean); + + return { + message: errorMessage, + location: { + pointer, + property + } + }; + }); + } +} + +module.exports = { + JsonSchemaValidator, + getSchemaVersion, + META_SCHEMA +}; diff --git a/lib/validators/json-schema.js b/lib/validators/json-schema.js index 7317e62a..bd6537b1 100644 --- a/lib/validators/json-schema.js +++ b/lib/validators/json-schema.js @@ -1,321 +1,17 @@ -const amanda = require('amanda'); -const deepEqual = require('deep-equal'); -const tv4 = require('tv4'); -const jsonPointer = require('json-pointer'); - -const parseJson = require('../utils/parseJson'); -const metaSchemaV3 = require('../meta-schema-v3'); -const metaSchemaV4 = require('../meta-schema-v4'); -const errors = require('../errors'); -const { ValidationErrors } = require('./validation-errors'); - -const SCHEMA_V3 = 'http://json-schema.org/draft-03/schema'; -const SCHEMA_V4 = 'http://json-schema.org/draft-04/schema'; - -/** - * @param {Object} schema - * @returns {[Object, string] | null} Tuple of [schemaMeta, schemaVersion] - */ -const getSchemaMeta = (schema) => { - if (schema && schema.$schema && schema.$schema.includes(SCHEMA_V3)) { - return [metaSchemaV3, 'v3']; - } - - if (schema && schema.$schema && schema.$schema.includes(SCHEMA_V4)) { - return [metaSchemaV4, 'v4']; - } - - return null; -}; - -/** - * Returns a proper article for a given string. - * @param {string} str - * @returns {string} - */ -function getArticle(str) { - const vowels = ['a', 'e', 'i', 'o', 'u']; - return vowels.includes(str.toLowerCase()) ? 'an' : 'a'; -} - -const jsonSchemaOptions = { - singleError: false, - messages: { - minLength: (prop, val, validator) => - `The ${prop} property must be at least ${validator} characters long (currently ${val.length} characters long).`, - maxLength: (prop, val, validator) => - `The ${prop} property must not exceed ${validator} characters (currently${val.length} characters long).`, - length: (prop, val, validator) => - `The ${prop} property must be exactly ${validator} characters long (currently ${val.length} characters long).`, - format: (prop, val, validator) => - `The ${prop} property must be ${getArticle( - validator[0] - )} ${validator} (current value is ${JSON.stringify(val)}).`, - type: (prop, val, validator) => - `The ${prop} property must be ${getArticle( - validator[0] - )} ${validator} (current value is ${JSON.stringify(val)})."`, - except: (prop, val) => `The ${prop} property must not be ${val}.`, - minimum: (prop, val, validator) => - `The minimum value of the ${prop} must be ${validator} (current value is ${JSON.stringify( - val - )}).`, - maximum: (prop, val, validator) => - `The maximum value of the ${prop} must be ${validator} (current value is ${JSON.stringify( - val - )}).`, - pattern: (prop, val, validator) => - `The ${prop} value (${val}) does not match the ${validator} pattern.`, - maxItems: (prop, val, validator) => - `The ${prop} property must not contain more than ${validator} items (currently contains ${val.length} items).`, - minItems: (prop, val, validator) => - `The ${prop} property must contain at least ${validator} items (currently contains ${val.length} items).`, - divisibleBy: (prop, val, validator) => - `The ${prop} property is not divisible by ${validator} (current value is ${JSON.stringify( - val - )}).`, - uniqueItems: (prop) => `All items in the ${prop} property must be unique.` - } -}; +const { JsonSchemaLegacy } = require('./json-schema-legacy'); +const { JsonSchemaValidator, getSchemaVersion } = require('./json-schema-next'); class JsonSchema { - /** - * Constructs a JsonValidator and validates given data. - * @param {Object | string} schema - * @param {Object | string} data - */ - constructor(schema, data) { - this.schema = schema; - this.data = data; - - if (typeof this.data === 'string') { - try { - this.data = parseJson(this.data); - } catch (error) { - const outError = new errors.DataNotJsonParsableError( - `JSON validator: body: ${error.message}` - ); - outError.data = this.data; - throw outError; - } - } - - if (typeof this.schema === 'string') { - try { - this.schema = parseJson(this.schema); - } catch (error) { - const outError = new errors.SchemaNotJsonParsableError( - `JSON validator: schema: ${error.message}` - ); - outError.schema = this.schema; - throw outError; - } - } - - this.jsonSchemaVersion = null; - this.validateSchema(); - } - - validateSchema() { - const [metaSchema, schemaVersion] = getSchemaMeta(this.schema) || []; - - if (metaSchema) { - this.jsonSchemaVersion = schemaVersion; - - if (metaSchema.$schema) { - tv4.reset(); - tv4.addSchema('', metaSchema); - tv4.addSchema(metaSchema.$schema, metaSchema); - const validationResult = tv4.validateResult(this.schema, metaSchema); - if (!validationResult.valid) { - throw new errors.JsonSchemaNotValid( - `JSON schema is not valid draft ${this.jsonSchemaVersion}! ${validationResult.error.message} at path "${validationResult.error.dataPath}"` - ); - } - } - } else { - if (metaSchemaV3.$schema) { - tv4.reset(); - tv4.addSchema('', metaSchemaV3); - tv4.addSchema(metaSchemaV3.$schema, metaSchemaV3); - const validationResult = tv4.validateResult(this.schema, metaSchemaV3); - - if (validationResult && validationResult.valid) { - this.jsonSchemaVersion = 'v3'; - return; - } - } - - if (metaSchemaV4.$schema) { - tv4.reset(); - tv4.addSchema('', metaSchemaV4); - tv4.addSchema(metaSchemaV4.$schema, metaSchemaV4); - const validationResult = tv4.validateResult(this.schema, metaSchemaV4); - - if (validationResult && validationResult.valid) { - this.jsonSchemaVersion = 'v4'; - return; - } - } - - if (this.jsonSchemaVersion === null) { - throw new errors.JsonSchemaNotValid( - 'JSON schema is not valid draft v3 or draft v4!' - ); - } - } - } - - validate() { - if ( - this.data !== null && - typeof this.data === 'object' && - this.schema.empty - ) { - this.output = { - length: 0, - errorMessages: {} - }; - return new ValidationErrors(this.output); - } - - const hasSameData = deepEqual(this.data, this.usedData, { strict: true }); - const hasSameSchema = hasSameData - ? deepEqual(this.schema, this.usedSchema, { strict: true }) - : true; - - if (!hasSameData || !hasSameSchema) { - this.output = this.validatePrivate(); - } - - return this.output; - } - - validatePrivate() { - this.usedData = this.data; - this.usedSchema = this.schema; - - switch (this.jsonSchemaVersion) { - case 'v3': - return this.validateSchemaV3(); - case 'v4': - return this.validateSchemaV4(); - default: - throw new Error("JSON schema version not identified, can't validate!"); - } - } - - /** - * Converts TV4 output to Gavel results. - */ - evaluateOutputToResults(data) { - if (!data) { - data = this.output; - } - - if (!data) { - return []; - } - - const results = Array.from({ length: data.length }, (_, index) => { - const item = data[index]; - const { message, property } = item; - let pathArray = []; - - if (property === null) { - pathArray = []; - } else if ( - Array.isArray(property) && - property.length === 1 && - [null, undefined].includes(property[0]) - ) { - pathArray = []; - } else { - pathArray = property; - } - - return { - message, - location: { - pointer: jsonPointer.compile(pathArray), - property - } - }; - }); - - return results; - } - - validateSchemaV3() { - try { - return amanda.validate( - this.data, - this.schema, - jsonSchemaOptions, - (error) => { - if (error && error.length > 0) { - for (let i = 0; i < error.length; i++) { - if (error[i].property === '') { - error[i].property = []; - } - } - this.errors = new ValidationErrors(error); - return this.errors; - } - } - ); - } catch (error) { - this.errors = new ValidationErrors({ - '0': { - property: [], - attributeValue: true, - message: `Validator internal error: ${error.message}`, - validatorName: 'error' - }, - length: 1, - errorMessages: {} - }); - - return this.errors; - } - } - - validateSchemaV4() { - const result = tv4.validateMultiple(this.data, this.schema); - const validationErrors = result.errors.concat(result.missing); - - const amandaCompatibleError = { - length: validationErrors.length, - errorMessages: {} - }; - - for (let index = 0; index < validationErrors.length; index++) { - const validationError = validationErrors[index]; - let error; - - if (validationError instanceof Error) { - error = validationError; - } else { - error = new Error('Missing schema'); - error.params = { key: validationError }; - error.dataPath = ''; - } - - const pathArray = jsonPointer - .parse(error.dataPath) - .concat(error.params.key || []); - const pointer = jsonPointer.compile(pathArray); - - amandaCompatibleError[index] = { - message: `At '${pointer}' ${error.message}`, - property: pathArray, - attributeValue: true, - validatorName: 'error' - }; - } - - this.errors = new ValidationErrors(amandaCompatibleError); - return this.errors; + constructor(jsonSchema) { + const jsonSchemaVersion = getSchemaVersion(jsonSchema); + const isLegacy = ['v3', 'v4'].includes(jsonSchemaVersion); + + // Instantiate different JSON Schema validators + // based on the JSON Schema Draft version. + // Both validators have the same API. + return isLegacy + ? new JsonSchemaLegacy(jsonSchema) + : new JsonSchemaValidator(jsonSchema); } } diff --git a/package-lock.json b/package-lock.json index 2eca1db1..9fe5fc90 100644 --- a/package-lock.json +++ b/package-lock.json @@ -557,7 +557,6 @@ "version": "6.10.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -2037,14 +2036,12 @@ "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fast-levenshtein": { "version": "2.0.6", @@ -3100,8 +3097,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -7834,8 +7830,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "q": { "version": "1.5.1", @@ -9014,7 +9009,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, "requires": { "punycode": "^2.1.0" } diff --git a/package.json b/package.json index d577640f..9b4dbef1 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ ] }, "dependencies": { + "ajv": "6.10.2", "amanda": "1.0.1", "caseless": "0.12.0", "clone": "2.1.2", diff --git a/test/fixtures/invalid-schema-v6.json b/test/fixtures/invalid-schema-v6.json new file mode 100644 index 00000000..2082e2e0 --- /dev/null +++ b/test/fixtures/invalid-schema-v6.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "http://json-schema.org/draft-06/schema#", + "type": "object", + "required": ["foo"], + "properties": { + "foo": { + "type": "any" + }, + "bar": { + "type": "string", + "enum": ["a", "b", "c"] + } + } +} diff --git a/test/fixtures/invalid-schema-v7.json b/test/fixtures/invalid-schema-v7.json new file mode 100644 index 00000000..aa62c10a --- /dev/null +++ b/test/fixtures/invalid-schema-v7.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://json-schema.org/draft-07/schema#", + "required": ["foo"], + "properties": { + "foo": { + "type": { + "not": "number" + } + } + } +} diff --git a/test/fixtures/valid-schema-v4.json b/test/fixtures/valid-schema-v4.json index b405ac85..baf6f059 100644 --- a/test/fixtures/valid-schema-v4.json +++ b/test/fixtures/valid-schema-v4.json @@ -1,19 +1,15 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Any validation failures are shown in the right-hand Messages pane.", - "type": "object", - "required": ["foo"], - "properties": { - "foo": { - "type": "number" - }, - "bar": { - "type": "string", - "enum": [ - "a", - "b", - "c" - ] - } + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Any validation failures are shown in the right-hand Messages pane.", + "type": "object", + "required": ["foo"], + "properties": { + "foo": { + "type": "number" + }, + "bar": { + "type": "string", + "enum": ["a", "b", "c"] } -} \ No newline at end of file + } +} diff --git a/test/fixtures/valid-schema-v6.json b/test/fixtures/valid-schema-v6.json new file mode 100644 index 00000000..a9d45549 --- /dev/null +++ b/test/fixtures/valid-schema-v6.json @@ -0,0 +1,11 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "http://json-schema.org/draft-06/schema#", + "type": ["object"], + "required": ["foo"], + "properties": { + "foo": { + "type": "number" + } + } +} diff --git a/test/fixtures/valid-schema-v7.json b/test/fixtures/valid-schema-v7.json new file mode 100644 index 00000000..c9f7b02d --- /dev/null +++ b/test/fixtures/valid-schema-v7.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://json-schema.org/draft-07/schema#", + "required": ["foo"], + "properties": { + "foo": { + "not": { + "type": "number" + } + } + } +} diff --git a/test/unit/validators/json-ajv.test.js b/test/unit/validators/json-ajv.test.js new file mode 100644 index 00000000..bf5f694e --- /dev/null +++ b/test/unit/validators/json-ajv.test.js @@ -0,0 +1,79 @@ +const { assert } = require('chai'); +const { JsonSchema } = require('../../../lib/validators/json-schema'); +const jsonSchema4 = require('../../fixtures/valid-schema-v4'); + +describe('JSON Schema (AJV)', () => { + describe('given JSON Schema Draft 4', () => { + describe('and the data is valid', () => { + let fn = null; + let validator; + + before(() => { + fn = () => { + validator = new JsonSchema(jsonSchema4, { + foo: 2, + bar: 'a' + }); + }; + }); + + it('should not throw any error', () => { + assert.doesNotThrow(fn); + }); + + it('should set @jsonSchemaVersion to v4', () => { + fn(); + assert.equal(validator.jsonSchemaVersion, 'v4'); + }); + + it('should not have any errors', () => { + assert.notProperty(validator, 'errors'); + }); + }); + + describe('and the data is invalid', () => { + let fn = null; + let validator; + + before(() => { + fn = () => { + validator = new JsonSchema(jsonSchema4, { + bar: 'a' + }); + validator.validate(); + }; + }); + + it('should not throw any error', () => { + assert.doesNotThrow(fn); + }); + + it('should set @jsonSchemaVersion to v4', () => { + fn(); + assert.equal(validator.jsonSchemaVersion, 'v4'); + }); + + describe('should return errors', () => { + it('should have exactly one error', () => { + assert.equal(validator.errors.length, 1); + }); + + it('should have a pointer', () => { + assert.propertyVal(validator.errors[0].location, 'pointer', '/foo'); + }); + + it('should have a property name', () => { + assert.propertyVal(validator.errors[0].location, 'property', 'foo'); + }); + + it('should have the error message about missing required property', () => { + assert.propertyVal( + validator.errors[0], + 'message', + `'foo' is a required property` + ); + }); + }); + }); + }); +}); diff --git a/test/unit/validators/json-schema-legacy.test.js b/test/unit/validators/json-schema-legacy.test.js new file mode 100644 index 00000000..7fc92fc4 --- /dev/null +++ b/test/unit/validators/json-schema-legacy.test.js @@ -0,0 +1,188 @@ +const { expect } = require('chai'); +const { + JsonSchemaLegacy +} = require('../../../lib/validators/json-schema-legacy'); + +const errorTypes = require('../../../lib/errors'); +const invalidJsonSchema3 = require('../../fixtures/invalid-schema-v3'); +const validJsonSchema3 = require('../../fixtures/valid-schema-v3'); +const invalidJsonSchema4 = require('../../fixtures/invalid-schema-v4'); +const validJsonSchema4 = require('../../fixtures/valid-schema-v4'); + +describe('JSON Schema (legacy)', () => { + /** + * V3 + */ + describe('given JSON Schema Draft 3', () => { + describe('and the schema is invalid', () => { + let init; + + before(() => { + init = () => new JsonSchemaLegacy(invalidJsonSchema3); + }); + + it('should throw an error about the invalid schema', () => { + expect(init).to.throw(errorTypes.JsonSchemaNotValid); + }); + }); + + describe('and the schema is valid', () => { + let init; + let validator; + + before(() => { + init = () => { + validator = new JsonSchemaLegacy(validJsonSchema3); + }; + }); + + it('should not throw any errors', () => { + expect(init).not.to.throw(); + }); + + it('should recognize schema version as v3', () => { + expect(validator).to.have.property('jsonSchemaVersion', 'v3'); + }); + + describe('given validating data', () => { + describe('and the data is invalid', () => { + let errors; + const data = { + foo: 'wrong value type' + }; + + before(() => { + errors = validator.validate(data); + }); + + describe('should return validation errors', () => { + it('should have exactly 1 error', () => { + expect(errors).to.have.lengthOf(1); + }); + + it('should have an error message', () => { + expect(errors[0].message).to.match( + /^The foo property must be a number \(current value is "wrong value type"\)/ + ); + }); + + it('should have a pointer', () => { + expect(errors[0]).to.have.nested.property( + 'location.pointer', + '/foo' + ); + }); + + it('should have a property name', () => { + expect(errors[0].location.property).to.deep.equal(['foo']); + }); + }); + }); + + describe('and the data is valid', () => { + let errors; + const data = { + foo: 123 + }; + + before(() => { + errors = validator.validate(data); + }); + + it('should return no errors', () => { + expect(errors).to.have.lengthOf(0); + }); + }); + }); + }); + }); + + /** + * V4 + */ + describe('given JSON Schema Draft 4', () => { + describe('and the schema is invalid', () => { + let init; + + before(() => { + init = () => new JsonSchemaLegacy(invalidJsonSchema4); + }); + + it('should throw an error about the invalid schema', () => { + expect(init).to.throw(errorTypes.JsonSchemaNotValid); + }); + }); + + describe('and the schema is valid', () => { + let init; + let validator; + + before(() => { + init = () => { + validator = new JsonSchemaLegacy(validJsonSchema4); + }; + }); + + it('should not throw any errors', () => { + expect(init).not.to.throw(); + }); + + it('should recognize schema version as v4', () => { + expect(validator).to.have.property('jsonSchemaVersion', 'v4'); + }); + + describe('given validating data', () => { + describe('and the data is invalid', () => { + let errors; + const data = { + foo: 'wrong value type', + b: 'z' // DOES NOT RESPECT ENUM HERE. THINKS THIS IS VALID. + }; + + before(() => { + errors = validator.validate(data); + }); + + describe('should return validation errors', () => { + it('should have 2 error', () => { + expect(errors).to.have.lengthOf(2); + }); + + it('should have an error message', () => { + expect(errors[0].message).to.equal( + `At '/foo' Invalid type: string (expected number)` + ); + }); + + it('should have a pointer', () => { + expect(errors[0]).to.have.nested.property( + 'location.pointer', + '/foo' + ); + }); + + it('should have a property name', () => { + expect(errors[0].location.property).to.deep.equal(['foo']); + }); + }); + }); + + describe('and the data is valid', () => { + let errors; + const data = { + foo: 123, + bar: 'a' + }; + + before(() => { + errors = validator.validate(data); + }); + + it('should return no errors', () => { + expect(errors).to.have.lengthOf(0); + }); + }); + }); + }); + }); +}); diff --git a/test/unit/validators/json-schema-next.test.js b/test/unit/validators/json-schema-next.test.js new file mode 100644 index 00000000..dd3fcbb1 --- /dev/null +++ b/test/unit/validators/json-schema-next.test.js @@ -0,0 +1,206 @@ +const { expect } = require('chai'); +const { + JsonSchemaValidator +} = require('../../../lib/validators/json-schema-next'); + +const errorTypes = require('../../../lib/errors'); +const invalidJsonSchema6 = require('../../fixtures/invalid-schema-v6'); +const validJsonSchema6 = require('../../fixtures/valid-schema-v6'); +const invalidJsonSchema7 = require('../../fixtures/invalid-schema-v7'); +const validJsonSchema7 = require('../../fixtures/valid-schema-v7'); + +describe('JSON Schema (next)', () => { + /** + * Unsupported version + */ + describe('given unsupported JSON Schema Draft version', () => { + let init; + + before(() => { + init = () => + new JsonSchemaValidator({ + $schema: 'http://json-schema.org/draft-02/schema' + }); + }); + + it('should throw an error about unsupported schema version', () => { + expect(init).to.throw(errorTypes.JsonSchemaNotSupported); + }); + }); + + /** + * Draft 6 + */ + describe('given JSON Schema Draft 6', () => { + describe('and the schema is invalid', () => { + let init; + + before(() => { + init = () => new JsonSchemaValidator(invalidJsonSchema6); + }); + + it('should throw an error about invalid schema', () => { + expect(init).to.throw(errorTypes.JsonSchemaNotValid); + }); + }); + + describe('and the schema is valid', () => { + let init; + let validator; + + before(() => { + init = () => { + validator = new JsonSchemaValidator(validJsonSchema6); + }; + }); + + it('should not throw any errors', () => { + expect(init).not.to.throw(); + }); + + it('should recognize schema version as v6', () => { + expect(validator).to.have.property('jsonSchemaVersion', 'v6'); + }); + + describe('given validating data', () => { + describe('and the data is valid', () => { + let errors; + const data = { + foo: 23 + }; + + before(() => { + errors = validator.validate(data); + }); + + it('should not return any errors', () => { + expect(errors).to.have.lengthOf(0); + }); + }); + + describe('and the data is invalid', () => { + let errors; + const data = { + foo: 'invalid-value' + }; + + before(() => { + errors = validator.validate(data); + }); + + describe('should return errors', () => { + it('should return exactly one error', () => { + expect(errors).to.have.lengthOf(1); + }); + + it('should contain the error message', () => { + expect(errors[0]).to.have.property( + 'message', + 'data/foo should be number' + ); + }); + + it('should contain the pointer', () => { + expect(errors[0]).to.have.nested.property( + 'location.pointer', + '/foo' + ); + }); + + it('should contain the property name', () => { + expect(errors[0].location.property).to.deep.equal(['foo']); + }); + }); + }); + }); + }); + }); + + /** + * Draft 7 + */ + describe('given JSON Schema Draft 7', () => { + describe('and the schema is invalid', () => { + let init; + + before(() => { + init = () => new JsonSchemaValidator(invalidJsonSchema7); + }); + + it('should throw an error about invalid schema', () => { + expect(init).to.throw(errorTypes.JsonSchemaNotValid); + }); + }); + + describe('and the schema is valid', () => { + let init; + let validator; + + before(() => { + init = () => { + validator = new JsonSchemaValidator(validJsonSchema7); + }; + }); + + it('should not throw any errors', () => { + expect(init).not.to.throw(); + }); + + it('should recognize schema version as v7', () => { + expect(validator).to.have.property('jsonSchemaVersion', 'v7'); + }); + + describe('given validating data', () => { + describe('and the data is valid', () => { + let errors; + const data = { + foo: 'valid-value' + }; + + before(() => { + errors = validator.validate(data); + }); + + it('should not return any errors', () => { + expect(errors).to.have.lengthOf(0); + }); + }); + + describe('and the data is invalid', () => { + let errors; + const data = { + foo: 3 + }; + + before(() => { + errors = validator.validate(data); + }); + + describe('should return errors', () => { + it('should return exactly one error', () => { + expect(errors).to.have.lengthOf(1); + }); + + it('should contain the error message', () => { + expect(errors[0]).to.have.property( + 'message', + 'data/foo should NOT be valid' + ); + }); + + it('should contain the pointer', () => { + expect(errors[0]).to.have.nested.property( + 'location.pointer', + '/foo' + ); + }); + + it('should contain the property name', () => { + expect(errors[0].location.property).to.deep.equal(['foo']); + }); + }); + }); + }); + }); + }); +}); diff --git a/test/unit/validators/json-schema.test.js b/test/unit/validators/json-schema.test.js index 98170c9f..c7df8cd1 100644 --- a/test/unit/validators/json-schema.test.js +++ b/test/unit/validators/json-schema.test.js @@ -71,7 +71,7 @@ describe('JsonSchema', () => { assert.isTrue(validator.errors instanceof ValidationErrors); }); - it('should return some errors', () => { + it.only('should return some errors', () => { assert.notEqual(validatorReturn.length, 0); }); From e82a1e2e0f6f4886adeab69e1af750dea473d1b8 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Wed, 27 Nov 2019 11:28:36 +0100 Subject: [PATCH 02/20] refactor: stores JSON Schema Draft versions as "draftV{x}" --- lib/validators/json-schema-legacy.js | 2 +- lib/validators/json-schema-next.js | 18 ++++++++---------- lib/validators/json-schema.js | 2 +- .../unit/validators/json-schema-legacy.test.js | 6 +++--- test/unit/validators/json-schema-next.test.js | 6 +++--- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/lib/validators/json-schema-legacy.js b/lib/validators/json-schema-legacy.js index 51c36d2e..3d543130 100644 --- a/lib/validators/json-schema-legacy.js +++ b/lib/validators/json-schema-legacy.js @@ -57,7 +57,7 @@ const jsonSchemaOptions = { class JsonSchemaLegacy extends JsonSchemaValidator { validateSchema() { const { jsonSchema, jsonMetaSchema } = this; - const metaSchema = jsonMetaSchema || META_SCHEMA.v3; + const metaSchema = jsonMetaSchema || META_SCHEMA.draftV3; tv4.reset(); tv4.addSchema('', metaSchema); diff --git a/lib/validators/json-schema-next.js b/lib/validators/json-schema-next.js index 5ade9bbe..82ddbbcd 100644 --- a/lib/validators/json-schema-next.js +++ b/lib/validators/json-schema-next.js @@ -7,17 +7,17 @@ const metaSchemaV3 = require('../meta-schema-v3'); const errors = require('../errors'); const SCHEMA_VERSIONS = { - v3: 'http://json-schema.org/draft-03/schema', - v4: 'http://json-schema.org/draft-04/schema', - v6: 'http://json-schema.org/draft-06/schema', - v7: 'http://json-schema.org/draft-07/schema' + draftV3: 'http://json-schema.org/draft-03/schema', + draftV4: 'http://json-schema.org/draft-04/schema', + draftV6: 'http://json-schema.org/draft-06/schema', + draftV7: 'http://json-schema.org/draft-07/schema' }; const META_SCHEMA = { - v3: metaSchemaV3, - v4: metaSchemaV4, - v6: metaSchemaV6, - v7: metaSchemaV7 + draftV3: metaSchemaV3, + draftV4: metaSchemaV4, + draftV6: metaSchemaV6, + draftV7: metaSchemaV7 }; /** @@ -70,8 +70,6 @@ class JsonSchemaValidator { validateSchema() { const { jsonSchemaVersion, jsonSchema } = this; let isSchemaValid = true; - - // use AJV to validate modern schema (6/7) const ajv = new Ajv(); const metaSchema = META_SCHEMA[jsonSchemaVersion]; diff --git a/lib/validators/json-schema.js b/lib/validators/json-schema.js index bd6537b1..0395dcda 100644 --- a/lib/validators/json-schema.js +++ b/lib/validators/json-schema.js @@ -4,7 +4,7 @@ const { JsonSchemaValidator, getSchemaVersion } = require('./json-schema-next'); class JsonSchema { constructor(jsonSchema) { const jsonSchemaVersion = getSchemaVersion(jsonSchema); - const isLegacy = ['v3', 'v4'].includes(jsonSchemaVersion); + const isLegacy = ['draftV3', 'draftV4'].includes(jsonSchemaVersion); // Instantiate different JSON Schema validators // based on the JSON Schema Draft version. diff --git a/test/unit/validators/json-schema-legacy.test.js b/test/unit/validators/json-schema-legacy.test.js index 7fc92fc4..1ee9cf84 100644 --- a/test/unit/validators/json-schema-legacy.test.js +++ b/test/unit/validators/json-schema-legacy.test.js @@ -41,7 +41,7 @@ describe('JSON Schema (legacy)', () => { }); it('should recognize schema version as v3', () => { - expect(validator).to.have.property('jsonSchemaVersion', 'v3'); + expect(validator).to.have.property('jsonSchemaVersion', 'draftV3'); }); describe('given validating data', () => { @@ -128,14 +128,14 @@ describe('JSON Schema (legacy)', () => { }); it('should recognize schema version as v4', () => { - expect(validator).to.have.property('jsonSchemaVersion', 'v4'); + expect(validator).to.have.property('jsonSchemaVersion', 'draftV4'); }); describe('given validating data', () => { describe('and the data is invalid', () => { let errors; const data = { - foo: 'wrong value type', + foo: 'should be number', b: 'z' // DOES NOT RESPECT ENUM HERE. THINKS THIS IS VALID. }; diff --git a/test/unit/validators/json-schema-next.test.js b/test/unit/validators/json-schema-next.test.js index dd3fcbb1..20214dc1 100644 --- a/test/unit/validators/json-schema-next.test.js +++ b/test/unit/validators/json-schema-next.test.js @@ -59,7 +59,7 @@ describe('JSON Schema (next)', () => { }); it('should recognize schema version as v6', () => { - expect(validator).to.have.property('jsonSchemaVersion', 'v6'); + expect(validator).to.have.property('jsonSchemaVersion', 'draftV6'); }); describe('given validating data', () => { @@ -81,7 +81,7 @@ describe('JSON Schema (next)', () => { describe('and the data is invalid', () => { let errors; const data = { - foo: 'invalid-value' + foo: 'should be number' }; before(() => { @@ -147,7 +147,7 @@ describe('JSON Schema (next)', () => { }); it('should recognize schema version as v7', () => { - expect(validator).to.have.property('jsonSchemaVersion', 'v7'); + expect(validator).to.have.property('jsonSchemaVersion', 'draftV7'); }); describe('given validating data', () => { From 28d94b75ce40c3f1ab8ceb4af15ad2ab92872802 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Fri, 29 Nov 2019 10:52:53 +0100 Subject: [PATCH 03/20] refactor: sets implicit JSON Schema version, if not set --- lib/validators/json-schema-legacy.js | 9 +- lib/validators/json-schema-next.js | 65 +++++--- lib/validators/json-schema.js | 43 +++++- test/unit/validators/json-schema.test.js | 189 +++++++++++------------ 4 files changed, 176 insertions(+), 130 deletions(-) diff --git a/lib/validators/json-schema-legacy.js b/lib/validators/json-schema-legacy.js index 3d543130..50269f8e 100644 --- a/lib/validators/json-schema-legacy.js +++ b/lib/validators/json-schema-legacy.js @@ -57,6 +57,9 @@ const jsonSchemaOptions = { class JsonSchemaLegacy extends JsonSchemaValidator { validateSchema() { const { jsonSchema, jsonMetaSchema } = this; + + // In case schema version is unidentified, + // assume JSON Schema Draft V3. const metaSchema = jsonMetaSchema || META_SCHEMA.draftV3; tv4.reset(); @@ -69,13 +72,13 @@ class JsonSchemaLegacy extends JsonSchemaValidator { validate(data) { switch (this.jsonSchemaVersion) { - case 'v3': + case 'draftV3': return this.validateUsingAmanda(data); - case 'v4': + case 'draftV4': return this.validateUsingTV4(data); default: throw new Error( - 'Attempted to use JsonSchemaLegacy on non-legacy JSON Schema!' + `Attempted to use JsonSchemaLegacy on non-legacy JSON Schema ${this.jsonSchemaVersion}!` ); } } diff --git a/lib/validators/json-schema-next.js b/lib/validators/json-schema-next.js index 82ddbbcd..2a448f03 100644 --- a/lib/validators/json-schema-next.js +++ b/lib/validators/json-schema-next.js @@ -1,4 +1,6 @@ const Ajv = require('ajv'); +const tv4 = require('tv4'); + const metaSchemaV6 = require('ajv/lib/refs/json-schema-draft-06.json'); const metaSchemaV7 = require('ajv/lib/refs/json-schema-draft-07.json'); @@ -24,34 +26,57 @@ const META_SCHEMA = { * Returns a JSON Schema Draft version of the given JSON Schema. */ const getSchemaVersion = (jsonSchema) => { - const jsonSchemaVersion = Object.keys(SCHEMA_VERSIONS).find((version) => { + const currentVersion = jsonSchema.$schema && jsonSchema.$schema; + return Object.keys(SCHEMA_VERSIONS).find((version) => { const jsonSchemaAnnotation = SCHEMA_VERSIONS[version]; - return ( - jsonSchema.$schema && jsonSchema.$schema.includes(jsonSchemaAnnotation) - ); + return currentVersion && currentVersion.includes(jsonSchemaAnnotation); }); +}; - if (jsonSchemaVersion == null) { - throw new errors.JsonSchemaNotSupported( - `Provided JSON Schema version is missing, or not supported. Please provide a JSON Schema Draft ${Object.keys( - SCHEMA_VERSIONS - ).join('/')}.` - ); - } - - return jsonSchemaVersion; +/** + * @deprecate + * Attempts to resolve a schema version for a JSON Schema + * without the explicit version. + */ +const getImplicitSchemaVersion = (jsonSchema) => { + const [schemaVersion] = [ + ['draftV3', metaSchemaV3], + ['draftV4', metaSchemaV4] + ].find(([_, metaSchema]) => { + tv4.reset(); + tv4.addSchema('', metaSchema); + tv4.addSchema(metaSchema.$schema, metaSchema); + const validationResult = tv4.validateResult(jsonSchema, metaSchema); + return validationResult.valid; + }) || [null, null]; + + return schemaVersion; }; class JsonSchemaValidator { constructor(jsonSchema) { this.jsonSchema = jsonSchema; - this.jsonSchemaVersion = getSchemaVersion(jsonSchema); + this.jsonSchemaVersion = + getSchemaVersion(this.jsonSchema) || + getImplicitSchemaVersion(this.jsonSchema); + + if (this.jsonSchemaVersion == null) { + const supportedVersions = Object.keys(SCHEMA_VERSIONS).join('/'); + + // Including all supported JSON Schema versions (even legacy) + // so that derived JsonSchemaLegacy class doesn't have to duplicate + // this version existence check. + throw new errors.JsonSchemaNotSupported( + `Expected a supported version of JSON Schema (${supportedVersions}).` + ); + } + this.jsonMetaSchema = this.getMetaSchema(); const isSchemaValid = this.validateSchema(); if (!isSchemaValid) { throw new errors.JsonSchemaNotValid( - `Provided JSON Schema is not a valid JSON Schema Draft ${this.jsonSchemaVersion}.` + `Provided JSON Schema is not a valid JSON Schema ${this.jsonSchemaVersion}.` ); } } @@ -69,13 +94,12 @@ class JsonSchemaValidator { */ validateSchema() { const { jsonSchemaVersion, jsonSchema } = this; - let isSchemaValid = true; const ajv = new Ajv(); const metaSchema = META_SCHEMA[jsonSchemaVersion]; ajv.addMetaSchema(metaSchema, 'meta'); - isSchemaValid = ajv.validateSchema(jsonSchema); + const isSchemaValid = ajv.validateSchema(jsonSchema); // Clean up the added meta schema ajv.removeSchema('meta'); @@ -94,9 +118,6 @@ class JsonSchemaValidator { // No need to validate schema again, already validated // in "validateSchema()" method. validateSchema: false, - // Make AJV point to the property in "error.dataPath", - // so it could be used as a complete pointer. - // errorDataPath: 'property', jsonPointers: true }); @@ -106,6 +127,9 @@ class JsonSchemaValidator { return (ajv.errors || []).map((ajvError) => { const errorMessage = ajv.errorsText([ajvError]); const { dataPath: pointer } = ajvError; + + // When AJV does not return a property name + // compose it from the pointer. const property = ajvError.params.missingProperty || pointer.split('/').filter(Boolean); @@ -123,5 +147,6 @@ class JsonSchemaValidator { module.exports = { JsonSchemaValidator, getSchemaVersion, + getImplicitSchemaVersion, META_SCHEMA }; diff --git a/lib/validators/json-schema.js b/lib/validators/json-schema.js index 0395dcda..04b26187 100644 --- a/lib/validators/json-schema.js +++ b/lib/validators/json-schema.js @@ -1,17 +1,48 @@ const { JsonSchemaLegacy } = require('./json-schema-legacy'); -const { JsonSchemaValidator, getSchemaVersion } = require('./json-schema-next'); +const { + JsonSchemaValidator, + getSchemaVersion, + getImplicitSchemaVersion +} = require('./json-schema-next'); +const errors = require('../errors'); +const parseJson = require('../utils/parseJson'); + +/** + * Resolve stringified JSON Schema to an Object. + * Validate invalid JSON Schema. + */ +function resolveJsonSchema(jsonSchema) { + let resolvedJsonSchema = jsonSchema; + + if (typeof jsonSchema === 'string') { + try { + resolvedJsonSchema = parseJson(jsonSchema); + } catch (error) { + const unparsableJsonSchemaError = new errors.SchemaNotJsonParsableError( + `Given JSON Schema is not a valid JSON. ${error.message}` + ); + unparsableJsonSchemaError.schema = jsonSchema; + throw unparsableJsonSchemaError; + } + } + + return resolvedJsonSchema; +} class JsonSchema { constructor(jsonSchema) { - const jsonSchemaVersion = getSchemaVersion(jsonSchema); - const isLegacy = ['draftV3', 'draftV4'].includes(jsonSchemaVersion); + const resolvedJsonSchema = resolveJsonSchema(jsonSchema); + const jsonSchemaVersion = + getSchemaVersion(resolvedJsonSchema) || + getImplicitSchemaVersion(resolvedJsonSchema); + const isLegacySchema = ['draftV3', 'draftV4'].includes(jsonSchemaVersion); // Instantiate different JSON Schema validators // based on the JSON Schema Draft version. // Both validators have the same API. - return isLegacy - ? new JsonSchemaLegacy(jsonSchema) - : new JsonSchemaValidator(jsonSchema); + return isLegacySchema + ? new JsonSchemaLegacy(resolvedJsonSchema) + : new JsonSchemaValidator(resolvedJsonSchema); } } diff --git a/test/unit/validators/json-schema.test.js b/test/unit/validators/json-schema.test.js index c7df8cd1..a9aeaeaa 100644 --- a/test/unit/validators/json-schema.test.js +++ b/test/unit/validators/json-schema.test.js @@ -25,127 +25,113 @@ describe('JsonSchema', () => { types.forEach((type) => { const data = dataForTypes[type]; - describe( - 'when i create new instance of validator with "' + - type + - '" type arguments', - () => { - let validator = null; - - beforeEach(() => { - validator = new JsonSchema(data.schema, data.actual); - }); + describe(`when i create new instance of validator with "${type}" type arguments`, () => { + let validator = null; - it('should not throw an exception', () => { - const fn = () => { - new JsonSchema(data.schema, data.actual); - }; - assert.doesNotThrow(fn); - }); + beforeEach(() => { + validator = new JsonSchema(data.schema); + }); - it('should set data to object', () => { - assert.equal(typeof validator.data, 'object'); - }); + it('should not throw an exception', () => { + const fn = () => new JsonSchema(data.schema); + assert.doesNotThrow(fn); + }); + + it('should parse schema to object', () => { + assert.equal(typeof validator.jsonSchema, 'object'); - it('should parse data to object which is json parsable', () => { - assert.doesNotThrow(() => JSON.stringify(validator.data)); + it('should parse schema to object which is json parsable', () => { + assert.doesNotThrow(() => JSON.stringify(validator.jsonSchema)); }); - it('should parse schema to object', () => { - assert.equal(typeof validator.schema, 'object'); + describe('when I run validate()', () => { + let validatorReturn = null; + let validatorReturnAgain = null; + let validatorReturnAfterDataChanged = null; - it('should parse schema to object which is json parsable', () => { - assert.doesNotThrow(() => JSON.stringify(validator.schema)); + beforeEach(() => { + validatorReturn = validator.validate(data.actual); }); - describe('when I run validate()', () => { - let validatorReturn = null; - let validatorReturnAgain = null; - let validatorReturnAfterDataChanged = null; + it('should set @errors', () => { + assert.isTrue(validator.errors instanceof ValidationErrors); + }); - beforeEach(() => { - validatorReturn = validator.validate(); - }); + it('should return some errors', () => { + assert.notEqual(validatorReturn.length, 0); + }); - it('should set @errors', () => { - assert.isTrue(validator.errors instanceof ValidationErrors); + describe('and run validate again', () => { + before(() => { + validatorReturnAgain = validator.validate(data.actual); }); - it.only('should return some errors', () => { - assert.notEqual(validatorReturn.length, 0); + it('errors should not change', () => { + assert.deepEqual( + JSON.parse(JSON.stringify(validatorReturnAgain)), + JSON.parse(JSON.stringify(validatorReturn)) + ); }); + }); + describe('when i change data', () => { describe('and run validate again', () => { before(() => { - validatorReturnAgain = validator.validate(); - }); - - it('errors should not change', () => { - assert.deepEqual( - JSON.parse(JSON.stringify(validatorReturnAgain)), - JSON.parse(JSON.stringify(validatorReturn)) + validatorReturnAfterDataChanged = validator.validate( + data.actual ); }); - }); - describe('when i change data', () => { - before(() => { - validator.data = JSON.parse(fixtures.sampleJson); + it('errors should change', () => { + assert.equal(validatorReturnAfterDataChanged.length, 0); }); + }); + }); - describe('and run validate again', () => { - before(() => { - validatorReturnAfterDataChanged = validator.validate(); - }); - it('errors should change', () => { - assert.equal(validatorReturnAfterDataChanged.length, 0); - }); - }); + describe('when i change schema', () => { + before(() => { + validator.jsonSchema = JSON.parse( + fixtures.sampleJsonSchemaNonStrict2 + ); }); - describe('when i change schema', () => { + describe('and run validate again', () => { + validatorReturnAfterDataChanged2 = null; before(() => { - validator.schema = JSON.parse( - fixtures.sampleJsonSchemaNonStrict2 + validatorReturnAfterDataChanged2 = validator.validate( + data.actual ); }); - describe('and run validate again', () => { - validatorReturnAfterDataChanged2 = null; - before(() => { - validatorReturnAfterDataChanged2 = validator.validate(); - }); - - it('errors should change', () => { - assert.notDeepEqual( - JSON.parse( - JSON.stringify(validatorReturnAfterDataChanged2) - ), - JSON.parse(JSON.stringify(validatorReturnAfterDataChanged)) - ); - }); + it('errors should change', () => { + assert.notDeepEqual( + JSON.parse(JSON.stringify(validatorReturnAfterDataChanged2)), + JSON.parse(JSON.stringify(validatorReturnAfterDataChanged)) + ); }); }); }); }); + }); - shared.shouldBehaveLikeAmandaToGavel(new JsonSchema('{}', '{}')); - } - ); + // shared.shouldBehaveLikeAmandaToGavel(new JsonSchema('{}')); + }); describe('when validation performed on actual empty object', () => { it('should return some errors', () => { validator = new JsonSchema( - JSON.parse(fixtures.sampleJsonSchemaNonStrict), - {} + JSON.parse(fixtures.sampleJsonSchemaNonStrict) ); - result = validator.validate(); - assert.notEqual(validator.validate().length, 0); + result = validator.validate({}); + assert.notEqual(result.length, 0); }); }); + /** + * @deprecate Stop testing implementation detail. + */ it('should have validateSchema method', () => { - validator = new JsonSchema({}, {}); + validator = new JsonSchema({}); assert.isDefined(validator.validateSchema); }); @@ -162,7 +148,7 @@ describe('JsonSchema', () => { it('should throw an error for "schema"', () => { const invalidStringifiedSchema = require('../../fixtures/invalid-stringified-schema'); const fn = () => { - new JsonSchema(invalidStringifiedSchema, {}); + new JsonSchema(invalidStringifiedSchema); }; assert.throw(fn); }); @@ -178,10 +164,11 @@ describe('JsonSchema', () => { fixtures.sampleJsonBodyTestingAmandaMessages ).length; validator = new JsonSchema( - fixtures.sampleJsonSchemaTestingAmandaMessages, + fixtures.sampleJsonSchemaTestingAmandaMessages + ); + results = validator.validate( fixtures.sampleJsonBodyTestingAmandaMessages ); - results = validator.validate(); }); it('contains all those schema defined messages', () => { @@ -206,7 +193,7 @@ describe('JsonSchema', () => { before(() => { const invalidSchema = require('../../fixtures/invalid-schema-v3'); fn = () => { - validator = new JsonSchema(invalidSchema, {}); + validator = new JsonSchema(invalidSchema); }; }); @@ -218,7 +205,7 @@ describe('JsonSchema', () => { try { fn(); } catch (e) { - assert.include(e.message, 'v3'); + assert.include(e.message, 'draftV3'); } }); }); @@ -228,7 +215,7 @@ describe('JsonSchema', () => { before(() => { const validSchema = require('../../fixtures/valid-schema-v3'); fn = () => { - validator = new JsonSchema(validSchema, {}); + validator = new JsonSchema(validSchema); }; }); @@ -238,7 +225,7 @@ describe('JsonSchema', () => { it('should set @jsonSchemaVersion to v3', () => { fn(); - assert.equal(validator.jsonSchemaVersion, 'v3'); + assert.equal(validator.jsonSchemaVersion, 'draftV3'); }); }); }); @@ -249,7 +236,7 @@ describe('JsonSchema', () => { before(() => { const invalidSchema = require('../../fixtures/invalid-schema-v4'); fn = () => { - validator = new JsonSchema(invalidSchema, {}); + validator = new JsonSchema(invalidSchema); }; }); @@ -261,7 +248,7 @@ describe('JsonSchema', () => { try { fn(); } catch (error) { - assert.include(error.message, 'v4'); + assert.include(error.message, 'draftV4'); } }); }); @@ -271,7 +258,7 @@ describe('JsonSchema', () => { before(() => { validSchema = require('../../fixtures/valid-schema-v4'); fn = () => { - validator = new JsonSchema(validSchema, {}); + validator = new JsonSchema(validSchema); }; }); @@ -281,7 +268,7 @@ describe('JsonSchema', () => { it('should set @jsonSchemaVersion to v4', () => { fn(); - assert.equal(validator.jsonSchemaVersion, 'v4'); + assert.equal(validator.jsonSchemaVersion, 'draftV4'); }); }); @@ -290,9 +277,9 @@ describe('JsonSchema', () => { let fn = null; before(() => { validSchema = require('../../fixtures/valid-schema-v3'); - delete validSchema['$schema']; + delete validSchema.$schema; fn = () => { - validator = new JsonSchema(validSchema, {}); + validator = new JsonSchema(validSchema); }; }); @@ -302,7 +289,7 @@ describe('JsonSchema', () => { it('should set @jsonSchemaVersion to v3', () => { fn(); - assert.equal(validator.jsonSchemaVersion, 'v3'); + assert.equal(validator.jsonSchemaVersion, 'draftV3'); }); }); @@ -310,9 +297,9 @@ describe('JsonSchema', () => { let fn = null; before(() => { validSchema = require('../../fixtures/valid-schema-v4'); - delete validSchema['$schema']; + delete validSchema.$schema; fn = () => { - validator = new JsonSchema(validSchema, {}); + validator = new JsonSchema(validSchema); }; }); @@ -322,7 +309,7 @@ describe('JsonSchema', () => { it('should set @jsonSchemaVersion to v4', () => { fn(); - assert.equal(validator.jsonSchemaVersion, 'v4'); + assert.equal(validator.jsonSchemaVersion, 'draftV4'); }); }); @@ -330,9 +317,9 @@ describe('JsonSchema', () => { let fn = null; before(() => { validSchema = require('../../fixtures/invalid-schema-v3-v4'); - delete validSchema['$schema']; + delete validSchema.$schema; fn = () => { - validator = new JsonSchema(validSchema, {}); + validator = new JsonSchema(validSchema); }; }); @@ -344,8 +331,8 @@ describe('JsonSchema', () => { try { fn(); } catch (error) { - assert.include(error.message, 'v3'); - assert.include(error.message, 'v4'); + assert.include(error.message, 'draftV3'); + assert.include(error.message, 'draftV4'); } }); }); From 1930ec5adb92bebe7a2939008b2285bc472b0a62 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Fri, 29 Nov 2019 11:11:52 +0100 Subject: [PATCH 04/20] refactor: parses given data in case of string in JsonSchemaValidator --- lib/validators/json-schema-legacy.js | 6 ++- lib/validators/json-schema-next.js | 24 ++++++++++- test/unit/validators/json-schema.test.js | 54 ++++++++++-------------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/lib/validators/json-schema-legacy.js b/lib/validators/json-schema-legacy.js index 50269f8e..baab4ec8 100644 --- a/lib/validators/json-schema-legacy.js +++ b/lib/validators/json-schema-legacy.js @@ -71,11 +71,13 @@ class JsonSchemaLegacy extends JsonSchemaValidator { } validate(data) { + const parsedData = this.parseData(data); + switch (this.jsonSchemaVersion) { case 'draftV3': - return this.validateUsingAmanda(data); + return this.validateUsingAmanda(parsedData); case 'draftV4': - return this.validateUsingTV4(data); + return this.validateUsingTV4(parsedData); default: throw new Error( `Attempted to use JsonSchemaLegacy on non-legacy JSON Schema ${this.jsonSchemaVersion}!` diff --git a/lib/validators/json-schema-next.js b/lib/validators/json-schema-next.js index 2a448f03..028690e5 100644 --- a/lib/validators/json-schema-next.js +++ b/lib/validators/json-schema-next.js @@ -7,6 +7,7 @@ const metaSchemaV7 = require('ajv/lib/refs/json-schema-draft-07.json'); const metaSchemaV4 = require('../meta-schema-v4'); const metaSchemaV3 = require('../meta-schema-v3'); const errors = require('../errors'); +const parseJson = require('../utils/parseJson'); const SCHEMA_VERSIONS = { draftV3: 'http://json-schema.org/draft-03/schema', @@ -107,10 +108,31 @@ class JsonSchemaValidator { return isSchemaValid; } + parseData(data) { + let resolvedData = data; + + if (typeof data === 'string') { + try { + resolvedData = parseJson(data); + } catch (error) { + console.log('failed json', data); + const dataError = new errors.DataNotJsonParsableError( + `Expected data to be a valid JSON, but got: ${data}. ${error.message}` + ); + error.data = data; + throw dataError; + } + } + + return resolvedData; + } + /** * Validates the given data. */ validate(data) { + const parsedData = this.parseData(data); + const ajv = new Ajv({ // Disable adding JSON Schema Draft 7 meta schema by default. // Allows to always add a meta schema depending on the schema version. @@ -121,7 +143,7 @@ class JsonSchemaValidator { jsonPointers: true }); - ajv.validate(this.jsonSchema, data); + ajv.validate(this.jsonSchema, parsedData); // Convert AJV validation errors to the Gavel public validation errors. return (ajv.errors || []).map((ajvError) => { diff --git a/test/unit/validators/json-schema.test.js b/test/unit/validators/json-schema.test.js index a9aeaeaa..584a74dc 100644 --- a/test/unit/validators/json-schema.test.js +++ b/test/unit/validators/json-schema.test.js @@ -45,31 +45,27 @@ describe('JsonSchema', () => { }); describe('when I run validate()', () => { - let validatorReturn = null; - let validatorReturnAgain = null; - let validatorReturnAfterDataChanged = null; + let errors = null; + let errorsAgain = null; + let errorsAfterDataChanged = null; beforeEach(() => { - validatorReturn = validator.validate(data.actual); - }); - - it('should set @errors', () => { - assert.isTrue(validator.errors instanceof ValidationErrors); + errors = validator.validate(data.actual); }); it('should return some errors', () => { - assert.notEqual(validatorReturn.length, 0); + assert.notEqual(errors.length, 0); }); describe('and run validate again', () => { before(() => { - validatorReturnAgain = validator.validate(data.actual); + errorsAgain = validator.validate(data.actual); }); it('errors should not change', () => { assert.deepEqual( - JSON.parse(JSON.stringify(validatorReturnAgain)), - JSON.parse(JSON.stringify(validatorReturn)) + JSON.parse(JSON.stringify(errorsAgain)), + JSON.parse(JSON.stringify(errors)) ); }); }); @@ -77,13 +73,13 @@ describe('JsonSchema', () => { describe('when i change data', () => { describe('and run validate again', () => { before(() => { - validatorReturnAfterDataChanged = validator.validate( - data.actual + errorsAfterDataChanged = validator.validate( + fixtures.sampleJson ); }); - it('errors should change', () => { - assert.equal(validatorReturnAfterDataChanged.length, 0); + it('should not return any errors', () => { + assert.equal(errorsAfterDataChanged.length, 0); }); }); }); @@ -96,17 +92,16 @@ describe('JsonSchema', () => { }); describe('and run validate again', () => { - validatorReturnAfterDataChanged2 = null; + errorsAfterDataChanged2 = null; + before(() => { - validatorReturnAfterDataChanged2 = validator.validate( - data.actual - ); + errorsAfterDataChanged2 = validator.validate(data.actual); }); it('errors should change', () => { assert.notDeepEqual( - JSON.parse(JSON.stringify(validatorReturnAfterDataChanged2)), - JSON.parse(JSON.stringify(validatorReturnAfterDataChanged)) + JSON.parse(JSON.stringify(errorsAfterDataChanged2)), + JSON.parse(JSON.stringify(errorsAfterDataChanged)) ); }); }); @@ -122,8 +117,8 @@ describe('JsonSchema', () => { validator = new JsonSchema( JSON.parse(fixtures.sampleJsonSchemaNonStrict) ); - result = validator.validate({}); - assert.notEqual(result.length, 0); + errors = validator.validate({}); + assert.notEqual(errors.length, 0); }); }); @@ -155,8 +150,7 @@ describe('JsonSchema', () => { }); describe('validate an object to check json_schema_options passed to Amanda', () => { - let results = null; - let error = null; + let errors = null; let messagesLength = null; before(() => { @@ -166,22 +160,20 @@ describe('JsonSchema', () => { validator = new JsonSchema( fixtures.sampleJsonSchemaTestingAmandaMessages ); - results = validator.validate( + errors = validator.validate( fixtures.sampleJsonBodyTestingAmandaMessages ); }); it('contains all those schema defined messages', () => { - assert.isNull(error); - assert.isObject(results); + assert.lengthOf(errors, messagesLength); assert.lengthOf( Object.keys( fixtures.sampleJsonSchemaTestingAmandaMessages.properties ), messagesLength ); - assert.propertyVal(results, 'length', messagesLength); - assert.lengthOf(results, messagesLength); + assert.lengthOf(errors, messagesLength); }); }); From cb8c01a229932b88dbaca13e5502bf07a32804d8 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Fri, 29 Nov 2019 11:26:12 +0100 Subject: [PATCH 05/20] refactor: adjusts "validateBody" to new JsonSchema call signature --- lib/units/validateBody.js | 12 ++-------- lib/validators/json-example.js | 27 ++++++++++++++--------- lib/validators/text-diff.js | 40 +++++++++++++++------------------- 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/lib/units/validateBody.js b/lib/units/validateBody.js index cf6a7487..f1935e3f 100644 --- a/lib/units/validateBody.js +++ b/lib/units/validateBody.js @@ -238,17 +238,9 @@ function validateBody(expected, actual) { const usesJsonSchema = ValidatorClass && ValidatorClass.name === 'JsonSchema'; const validator = ValidatorClass && - new ValidatorClass( - usesJsonSchema ? expected.bodySchema : expected.body, - actual.body - ); + new ValidatorClass(usesJsonSchema ? expected.bodySchema : expected.body); - // Calling "validate()" often updates an internal state of a validator. - // That state is later used to output the gavel-compliant results. - // Cannot remove until validators are refactored into simple functions. - // @see https://github.com/apiaryio/gavel.js/issues/150 - validator && validator.validate(); - const validationErrors = validator ? validator.evaluateOutputToResults() : []; + const validationErrors = validator ? validator.validate(actual.body) : []; errors.push(...validationErrors); return { diff --git a/lib/validators/json-example.js b/lib/validators/json-example.js index 0f7006fc..0739bed9 100644 --- a/lib/validators/json-example.js +++ b/lib/validators/json-example.js @@ -16,17 +16,25 @@ function getSchema(json) { } class JsonExample extends JsonSchema { + constructor(expected) { + // Generate JSON Schema from the given expected JSON data. + const jsonSchema = getSchema(expected); + super(jsonSchema); + } + /** - * Construct a BodyValidator, check data and choose the right validator. - * If actual and expected data are valid JSON, and a valid schema is given, - * choose JsonValidator, otherwise choose StringValidator. - * @param {string} expected - * @param {string} actual * @throw {MalformedDataError} when actual is not a String or when no schema provided and expected is not a String - * @throw {SchemaNotJsonParsableError} when given schema is not a json parsable string or valid json - * @throw {NotEnoughDataError} when at least one of expected data and json schema is not given */ - constructor(expected, actual) { + validate(actual) { + const { jsonSchema: expected } = this; + + console.log( + 'JsonExample: Validating', + JSON.stringify(actual, null, 2), + 'against', + JSON.stringify(expected, null, 2) + ); + if (typeof actual !== 'string') { const outError = new errors.MalformedDataError( 'JsonExample validator: provided actual data is not string' @@ -43,8 +51,7 @@ class JsonExample extends JsonSchema { throw outError; } - const schema = getSchema(expected); - super(schema, actual); + return super.validate(actual); } } diff --git a/lib/validators/text-diff.js b/lib/validators/text-diff.js index e9a38818..b913cb42 100644 --- a/lib/validators/text-diff.js +++ b/lib/validators/text-diff.js @@ -1,15 +1,7 @@ const errors = require('../errors'); class TextDiff { - constructor(expected, actual) { - if (typeof actual !== 'string') { - const outError = new errors.DataNotStringError( - 'String validator actual: input data is not string' - ); - outError.data = actual; - throw outError; - } - + constructor(expected) { if (typeof expected !== 'string') { const outError = new errors.DataNotStringError( 'String validator expected: input data is not string' @@ -19,24 +11,26 @@ class TextDiff { } this.expected = expected; - this.actual = actual; } - validate() { - this.valid = this.actual === this.expected; - return this.valid; - } - - evaluateOutputToResults() { - if (this.valid) { - return []; + validate(actual) { + if (typeof actual !== 'string') { + const outError = new errors.DataNotStringError( + 'String validator actual: input data is not string' + ); + outError.data = actual; + throw outError; } - return [ - { - message: 'Actual and expected data do not match.' - } - ]; + this.valid = actual === this.expected; + + return this.valid + ? [] + : [ + { + message: 'Actual and expected data do not match.' + } + ]; } } From f9f93576bf56b32690b8c817377e13a84a10cc3e Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Fri, 29 Nov 2019 11:30:31 +0100 Subject: [PATCH 06/20] refactor: adjusts "validateHeaders" to new JsonSchema call signature --- lib/units/validateHeaders.js | 6 +- lib/validators/headers-json-example.js | 42 +++++---- .../headers-json-example-validator.test.js | 90 ++++++++----------- test/unit/validators/text-diff.test.js | 30 +++---- 4 files changed, 73 insertions(+), 95 deletions(-) diff --git a/lib/units/validateHeaders.js b/lib/units/validateHeaders.js index 2098c86d..4ab18d2a 100644 --- a/lib/units/validateHeaders.js +++ b/lib/units/validateHeaders.js @@ -28,14 +28,14 @@ function validateHeaders(expected, actual) { expectedType === APIARY_JSON_HEADER_TYPE; const validator = hasJsonHeaders - ? new HeadersJsonExample(values.expected, values.actual) + ? new HeadersJsonExample(values.expected) : null; // if you don't call ".validate()", it never evaluates any results. - validator && validator.validate(); + const validationErrors = validator && validator.validate(values.actual); if (validator) { - errors.push(...validator.evaluateOutputToResults()); + errors.push(...validationErrors); } else { errors.push({ message: `\ diff --git a/lib/validators/headers-json-example.js b/lib/validators/headers-json-example.js index 659d72ad..5e0a3a09 100644 --- a/lib/validators/headers-json-example.js +++ b/lib/validators/headers-json-example.js @@ -8,7 +8,7 @@ const { } = require('../utils/schema-v4-generator'); const tv4ToHeadersMessage = require('../utils/tv4-to-headers-message'); -const prepareHeaders = (headers) => { +const resolveHeaders = (headers) => { if (typeof headers !== 'object') { return headers; } @@ -38,42 +38,40 @@ const getSchema = (json) => { }; class HeadersJsonExample extends JsonSchema { - constructor(expected, actual) { - if (typeof actual !== 'object') { - throw new errors.MalformedDataError('Actual is not an Object'); - } - + constructor(expected) { if (typeof expected !== 'object') { throw new errors.MalformedDataError('Expected is not an Object'); } - const preparedExpected = prepareHeaders(expected); - const preparedActual = prepareHeaders(actual); - const preparedSchema = getSchema(preparedExpected); + const resolvedExpected = resolveHeaders(expected); + const resolvedJsonSchema = getSchema(resolvedExpected); - if (preparedSchema && preparedSchema.properties) { + if (resolvedJsonSchema && resolvedJsonSchema.properties) { const skippedHeaders = ['date', 'expires']; skippedHeaders.forEach((headerName) => { - if (preparedSchema.properties[headerName]) { - delete preparedSchema.properties[headerName].enum; + if (resolvedJsonSchema.properties[headerName]) { + delete resolvedJsonSchema.properties[headerName].enum; } }); } - super(preparedSchema, preparedActual); + super(resolvedJsonSchema); - this.expected = preparedExpected; - this.actual = preparedActual; - this.schema = preparedSchema; + this.expected = resolvedExpected; + this.jsonSchema = resolvedJsonSchema; } - validate() { - const result = super.validate(); + validate(data) { + if (typeof data !== 'object') { + throw new errors.MalformedDataError('Actual is not an Object'); + } + + const results = super.validate(data); - if (result.length > 0) { - const resultCopy = clone(result, false); + if (results.length > 0) { + const resultCopy = clone(results, false); - for (let i = 0; i < result.length; i++) { + for (let i = 0; i < results.length; i++) { resultCopy[i].message = tv4ToHeadersMessage( resultCopy[i].message, this.expected @@ -83,7 +81,7 @@ class HeadersJsonExample extends JsonSchema { return resultCopy; } - return result; + return results; } } diff --git a/test/unit/validators/headers-json-example-validator.test.js b/test/unit/validators/headers-json-example-validator.test.js index 7c879552..17d0a3fe 100644 --- a/test/unit/validators/headers-json-example-validator.test.js +++ b/test/unit/validators/headers-json-example-validator.test.js @@ -16,7 +16,7 @@ describe('HeadersJsonExample', () => { describe('when I provede real data as non obejct', () => { it('should throw an exception', () => { const fn = () => { - headersValidator = new HeadersJsonExample({ header1: 'value1' }, ''); + headersValidator = new HeadersJsonExample({ header1: 'value1' }); }; assert.throw(fn, 'is not an Object'); }); @@ -25,7 +25,7 @@ describe('HeadersJsonExample', () => { describe('when I provede expected data as non obejct', () => { it('should throw an exception', () => { const fn = () => { - headersValidator = new HeadersJsonExample('', { header1: 'value1' }); + headersValidator = new HeadersJsonExample(''); }; assert.throw(fn, 'is not an Object'); }); @@ -45,15 +45,12 @@ describe('HeadersJsonExample', () => { describe('when provided real and expected headers are the same', () => { before(() => { - headersValidator = new HeadersJsonExample( - fixtures.sampleHeaders, - fixtures.sampleHeaders - ); + headersValidator = new HeadersJsonExample(fixtures.sampleHeaders); }); describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = headersValidator.validate(); + result = headersValidator.validate(fixtures.sampleHeaders); assert.equal(result.length, 0); }); }); @@ -61,73 +58,63 @@ describe('HeadersJsonExample', () => { describe('when provided real and expected headers differ in upper/lower-case state of keys', () => { before(() => { - headersValidator = new HeadersJsonExample( - fixtures.sampleHeaders, - fixtures.sampleHeadersMixedCase - ); + headersValidator = new HeadersJsonExample(fixtures.sampleHeaders); }); describe('and I run validate()', () => { it("shouldn't return any errors", () => { - result = headersValidator.validate(); - assert.equal(result.length, 0); + errors = headersValidator.validate(fixtures.sampleHeadersMixedCase); + assert.equal(errors.length, 0); }); }); }); describe('when provided real and expected headers differ in one value (real change) of a key different by upper/lower', () => { before(() => { - headersValidator = new HeadersJsonExample( - fixtures.sampleHeaders, - fixtures.sampleHeadersMixedCaseDiffers - ); + headersValidator = new HeadersJsonExample(fixtures.sampleHeaders); }); describe('and I run validate()', () => { it('should not return error', () => { - result = headersValidator.validate(); - assert.lengthOf(result, 0); + errors = headersValidator.validate( + fixtures.sampleHeadersMixedCaseDiffers + ); + assert.lengthOf(errors, 0); }); }); }); describe('when key is missing in provided headers', () => { beforeEach(() => { - headersValidator = new HeadersJsonExample( - fixtures.sampleHeaders, - fixtures.sampleHeadersMissing - ); + headersValidator = new HeadersJsonExample(fixtures.sampleHeaders); }); describe('and i run validate()', () => { it('should return 1 error', () => { - result = headersValidator.validate(); - assert.equal(result.length, 1); + errors = headersValidator.validate(fixtures.sampleHeadersMissing); + assert.equal(errors.length, 1); }); it('should have beautiful error message', () => { - result = headersValidator.validate(); - assert.equal(result[0].message, "Header 'header2' is missing"); + errors = headersValidator.validate(fixtures.sampleHeadersMissing); + assert.equal(errors[0].message, "Header 'header2' is missing"); }); }); }); describe('when value of content negotiation header in provided headers differs', () => { beforeEach(() => { - headersValidator = new HeadersJsonExample( - fixtures.sampleHeaders, - fixtures.sampleHeadersDiffers - ); + headersValidator = new HeadersJsonExample(fixtures.sampleHeaders); }); describe('and i run validate()', () => { it('should return 1 errors', () => { - result = headersValidator.validate(); - assert.equal(result.length, 1); + errors = headersValidator.validate(fixtures.sampleHeadersDiffers); + assert.equal(errors.length, 1); }); it('should have beautiful error message', () => { - result = headersValidator.validate(); + errors = headersValidator.validate(fixtures.sampleHeadersDiffers); assert.equal( - result[0].message, + errors[0].message, "Header 'content-type' has value 'application/fancy-madiatype' instead of 'application/json'" ); }); @@ -137,29 +124,26 @@ describe('HeadersJsonExample', () => { describe('when key is added to provided headers', () => { before(() => { - headersValidator = new HeadersJsonExample( - fixtures.sampleHeaders, - fixtures.sampleHeadersAdded - ); + headersValidator = new HeadersJsonExample(fixtures.sampleHeaders); }); describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = headersValidator.validate(); - assert.equal(result.length, 0); + errors = headersValidator.validate(fixtures.sampleHeadersAdded); + assert.equal(errors.length, 0); }); }); }); describe('when real is empty object and expected is proper object', () => { before(() => { - headersValidator = new HeadersJsonExample(fixtures.sampleHeaders, {}); + headersValidator = new HeadersJsonExample(fixtures.sampleHeaders); }); describe('and i run validate()', () => { it('should return 2 errors', () => { - result = headersValidator.validate(); - assert.equal(result.length, 2); + errors = headersValidator.validate({}); + assert.equal(errors.length, 2); }); }); }); @@ -167,15 +151,16 @@ describe('HeadersJsonExample', () => { describe('when non content negotiation header header values differs', () => { before(() => { headersValidator = new HeadersJsonExample( - fixtures.sampleHeadersNonContentNegotiation, - fixtures.sampleHeadersWithNonContentNegotiationChanged + fixtures.sampleHeadersNonContentNegotiation ); }); describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = headersValidator.validate(); - assert.equal(result.length, 0); + errors = headersValidator.validate( + fixtures.sampleHeadersWithNonContentNegotiationChanged + ); + assert.equal(errors.length, 0); }); }); }); @@ -183,15 +168,12 @@ describe('HeadersJsonExample', () => { describe('#validate()', () => { output = null; before(() => { - headersValidator = new HeadersJsonExample( - fixtures.sampleHeaders, - fixtures.sampleHeadersMissing - ); - output = headersValidator.validate(); + headersValidator = new HeadersJsonExample(fixtures.sampleHeaders); + errors = headersValidator.validate(fixtures.sampleHeadersMissing); }); it('should return an obejct', () => { - assert.isObject(output); + assert.isObject(errors); }); }); diff --git a/test/unit/validators/text-diff.test.js b/test/unit/validators/text-diff.test.js index a86ed9fc..4a162af7 100644 --- a/test/unit/validators/text-diff.test.js +++ b/test/unit/validators/text-diff.test.js @@ -6,7 +6,7 @@ describe('TextDiff', () => { describe('when expected non-string data', () => { it('should throw an exception', () => { const fn = () => { - new TextDiff(null, ''); + new TextDiff(null); }; expect(fn).to.throw(); }); @@ -15,7 +15,7 @@ describe('TextDiff', () => { describe('when given non-string actual data', () => { it('should throw an exception', () => { const fn = () => { - new TextDiff('', null); + new TextDiff(''); }; expect(fn).to.throw(); }); @@ -25,13 +25,13 @@ describe('TextDiff', () => { const expected = 'Iñtërnâtiônàlizætiøn☃'; it('should resolve on matching actual string', () => { - const validator = new TextDiff(expected, expected); - expect(validator.validate()).to.be.true; + const validator = new TextDiff(expected); + expect(validator.validate(expected)).to.be.true; }); it('should reject on non-matching actual string', () => { - const validator = new TextDiff(expected, 'Nâtiônàl'); - expect(validator.validate()).to.be.false; + const validator = new TextDiff(expected); + expect(validator.validate('Nâtiônàl')).to.be.false; }); }); @@ -39,21 +39,20 @@ describe('TextDiff', () => { const expected = 'john'; it('should resolve when given matching actual data', () => { - const validator = new TextDiff(expected, 'john'); - expect(validator.validate()).to.be.true; + const validator = new TextDiff(expected); + expect(validator.validate('john')).to.be.true; }); it('should reject when given non-matching actual data', () => { - const validator = new TextDiff(expected, 'barry'); - expect(validator.validate()).to.be.false; + const validator = new TextDiff(expected); + expect(validator.validate('barry')).to.be.false; }); }); describe('when evaluating output to results', () => { describe('when expected and actual data match', () => { - const validator = new TextDiff('john', 'john'); - validator.validate(); - const result = validator.evaluateOutputToResults(); + const validator = new TextDiff('john'); + const result = validator.validate('john'); it('should return an empty array', () => { expect(result).to.be.instanceOf(Array); @@ -62,9 +61,8 @@ describe('TextDiff', () => { }); describe('when expected and actual data do not match', () => { - const validator = new TextDiff('john', 'barry'); - validator.validate(); - const result = validator.evaluateOutputToResults(); + const validator = new TextDiff('john'); + const result = validator.validate('barry'); it('should return an array', () => { expect(result).to.be.instanceOf(Array); From e8eadf9c961e16522fce1ba6f3c4ab62b0288a1a Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Fri, 29 Nov 2019 13:13:51 +0100 Subject: [PATCH 07/20] refactor: adjusts "HeadersJsonExample" to new JsonSchema signature --- lib/validators/headers-json-example.js | 7 ++++--- .../headers-json-example-validator.test.js | 17 ++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/validators/headers-json-example.js b/lib/validators/headers-json-example.js index 5e0a3a09..0682779e 100644 --- a/lib/validators/headers-json-example.js +++ b/lib/validators/headers-json-example.js @@ -1,7 +1,7 @@ const clone = require('clone'); const errors = require('../errors'); -const { JsonSchema } = require('./json-schema'); +const { JsonSchemaLegacy } = require('./json-schema-legacy'); const { SchemaV4Generator, SchemaV4Properties @@ -37,7 +37,7 @@ const getSchema = (json) => { return schemaGenerator.generate(); }; -class HeadersJsonExample extends JsonSchema { +class HeadersJsonExample extends JsonSchemaLegacy { constructor(expected) { if (typeof expected !== 'object') { throw new errors.MalformedDataError('Expected is not an Object'); @@ -66,7 +66,8 @@ class HeadersJsonExample extends JsonSchema { throw new errors.MalformedDataError('Actual is not an Object'); } - const results = super.validate(data); + const resolvedData = resolveHeaders(data); + const results = super.validate(resolvedData); if (results.length > 0) { const resultCopy = clone(results, false); diff --git a/test/unit/validators/headers-json-example-validator.test.js b/test/unit/validators/headers-json-example-validator.test.js index 17d0a3fe..c199714c 100644 --- a/test/unit/validators/headers-json-example-validator.test.js +++ b/test/unit/validators/headers-json-example-validator.test.js @@ -4,7 +4,6 @@ const { HeadersJsonExample } = require('../../../lib/validators/headers-json-example'); const fixtures = require('../../fixtures'); -const shared = require('../support/amanda-to-gavel-shared'); describe('HeadersJsonExample', () => { headersValidator = {}; @@ -16,7 +15,7 @@ describe('HeadersJsonExample', () => { describe('when I provede real data as non obejct', () => { it('should throw an exception', () => { const fn = () => { - headersValidator = new HeadersJsonExample({ header1: 'value1' }); + headersValidator = new HeadersJsonExample(''); }; assert.throw(fn, 'is not an Object'); }); @@ -34,10 +33,7 @@ describe('HeadersJsonExample', () => { describe('when I provide correct data', () => { it('should not throw an exception', () => { const fn = () => { - headersValidator = new HeadersJsonExample( - { header1: 'value1' }, - { header1: 'value1' } - ); + headersValidator = new HeadersJsonExample({ header1: 'value1' }); }; assert.doesNotThrow(fn); }); @@ -50,8 +46,9 @@ describe('HeadersJsonExample', () => { describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = headersValidator.validate(fixtures.sampleHeaders); - assert.equal(result.length, 0); + errors = headersValidator.validate(fixtures.sampleHeaders); + console.log({ errors }); + assert.equal(errors.length, 0); }); }); }); @@ -173,9 +170,7 @@ describe('HeadersJsonExample', () => { }); it('should return an obejct', () => { - assert.isObject(errors); + assert.isArray(errors); }); }); - - shared.shouldBehaveLikeAmandaToGavel(new HeadersJsonExample({}, {})); }); From ae746aea2a239cce1f219b8667dda9d40843e8c0 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Fri, 29 Nov 2019 13:24:35 +0100 Subject: [PATCH 08/20] refactor: removes "amanda-to-gavel-shared" test suites --- test/unit/support/amanda-to-gavel-shared.js | 72 ---------------- test/unit/validators/json-example.test.js | 93 ++++++--------------- test/unit/validators/json-schema.test.js | 1 - 3 files changed, 26 insertions(+), 140 deletions(-) delete mode 100644 test/unit/support/amanda-to-gavel-shared.js diff --git a/test/unit/support/amanda-to-gavel-shared.js b/test/unit/support/amanda-to-gavel-shared.js deleted file mode 100644 index 9c76ae01..00000000 --- a/test/unit/support/amanda-to-gavel-shared.js +++ /dev/null @@ -1,72 +0,0 @@ -/* eslint-disable */ -const validators = require('../../../lib/validators'); -const fixtures = require('../../fixtures'); -const jsonPointer = require('json-pointer'); -const { assert } = require('chai'); - -exports.shouldBehaveLikeAmandaToGavel = (instance) => { - describe('.evaluateOutputToResults()', () => { - output = null; - - describe('if data is null', () => { - before(() => { - data = null; - output = instance.evaluateOutputToResults(data); - }); - it('should set no messages to results', () => { - assert.equal(output.length, 0); - }); - }); - - describe("if data is Tully's sanitized pseudo amanda error with length 0", () => { - before(() => { - data = fixtures.emptyAmandaError; - }); - }); - - describe('if data is an amanda error', () => { - before(() => { - data = JSON.parse(fixtures.sampleAmandaError); - output = instance.evaluateOutputToResults(data); - }); - - it('should return an array', () => { - assert.isArray(output); - }); - }); - - describe('first element in results array', () => { - item = null; - before(() => { - item = output[0]; - }); - - it('should be an object', () => { - assert.isObject(item); - }); - - const props = ['message', 'location']; - props.forEach((key) => { - it('should have "' + key + '"', () => { - assert.include(Object.keys(item), key); - }); - }); - - describe('pointer key value', () => { - value = null; - before(() => { - value = item.location.pointer; - }); - - it('should be a string', () => { - assert.isString(value); - }); - - it('should be a parseable JSON poitner', () => { - const parsedPointer = jsonPointer.parse(value); - assert.isArray(parsedPointer); - }); - }); - }); - }); -}; diff --git a/test/unit/validators/json-example.test.js b/test/unit/validators/json-example.test.js index 16add7e1..eed13699 100644 --- a/test/unit/validators/json-example.test.js +++ b/test/unit/validators/json-example.test.js @@ -2,7 +2,6 @@ const { assert } = require('chai'); const { JsonExample } = require('../../../lib/validators/json-example'); const { JsonSchema } = require('../../../lib/validators/json-schema'); -const shared = require('../support/amanda-to-gavel-shared'); const fixtures = require('../../fixtures'); describe('JsonExample', () => { @@ -23,22 +22,7 @@ describe('JsonExample', () => { describe('when I provide string as real with JSONized string', () => { it('should not throw exception', () => { fn = () => { - bodyValidator = new JsonExample( - '{"header1": "value1"}', - '"Number of profiles deleted: com.viacom.auth.infrastructure.DocumentsUpdated@1"' - ); - }; - assert.doesNotThrow(fn); - }); - }); - - describe('when I provide string as expected with JSONized string', () => { - it('should not throw exception', () => { - const fn = () => { - bodyValidator = new JsonExample( - '"Number of profiles deleted: com.viacom.auth.infrastructure.DocumentsUpdated@1"', - '{"header1": "value1"}' - ); + bodyValidator = new JsonExample('{"header1": "value1"}'); }; assert.doesNotThrow(fn); }); @@ -48,7 +32,6 @@ describe('JsonExample', () => { it('should not throw exception', () => { const fn = () => { bodyValidator = new JsonExample( - '"Number of profiles deleted: com.viacom.auth.infrastructure.DocumentsUpdated@1"', '"Number of profiles deleted: com.viacom.auth.infrastructure.DocumentsUpdated@1"' ); }; @@ -72,10 +55,7 @@ describe('JsonExample', () => { describe('when I provide correct data', () => { it('should not throw exception', () => { const fn = () => { - bodyValidator = new JsonExample( - '{"header1": "value1"}', - '{"header1": "value1"}' - ); + bodyValidator = new JsonExample('{"header1": "value1"}'); }; assert.doesNotThrow(fn); }); @@ -83,22 +63,16 @@ describe('JsonExample', () => { describe('when expected and real data are json parsable', () => { before(() => { - bodyValidator = new JsonExample( - fixtures.sampleJson, - fixtures.sampleJson - ); + bodyValidator = new JsonExample(fixtures.sampleJson); }); describe('when provided real and expected data are the same', () => { before(() => { - bodyValidator = new JsonExample( - fixtures.sampleJson, - fixtures.sampleJson - ); + bodyValidator = new JsonExample(fixtures.sampleJson); }); describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = bodyValidator.validate(); + result = bodyValidator.validate(fixtures.sampleJson); assert.equal(result.length, 0); }); }); @@ -107,14 +81,11 @@ describe('JsonExample', () => { describe('when key is missing in provided real data', () => { before(() => { - bodyValidator = new JsonExample( - fixtures.sampleJson, - fixtures.sampleJsonSimpleKeyMissing - ); + bodyValidator = new JsonExample(fixtures.sampleJson); }); describe('and i run validate()', () => { it('should return 1 errors', () => { - result = bodyValidator.validate(); + result = bodyValidator.validate(fixtures.sampleJsonSimpleKeyMissing); assert.equal(result.length, 1); }); }); @@ -134,13 +105,12 @@ describe('JsonExample', () => { describe('when value in provided and expected data differs', () => { before(() => { bodyValidator = new JsonExample( - fixtures.sampleJsonSimpleKeyValueDiffers, - fixtures.sampleJson + fixtures.sampleJsonSimpleKeyValueDiffers ); }); describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = bodyValidator.validate(); + result = bodyValidator.validate(fixtures.sampleJson); assert.equal(result.length, 0); }); }); @@ -148,14 +118,11 @@ describe('JsonExample', () => { describe('when key is added to provided data', () => { before(() => { - bodyValidator = new JsonExample( - fixtures.sampleJson, - fixtures.sampleJsonComplexKeyAdded - ); + bodyValidator = new JsonExample(fixtures.sampleJson); }); describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = bodyValidator.validate(); + result = bodyValidator.validate(fixtures.sampleJsonComplexKeyAdded); assert.equal(result.length, 0); }); }); @@ -163,14 +130,11 @@ describe('JsonExample', () => { describe('when key value is a empty string', () => { before(() => { - bodyValidator = new JsonExample( - fixtures.emptyStringJson, - fixtures.emptyStringJson - ); + bodyValidator = new JsonExample(fixtures.emptyStringJson); }); describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = bodyValidator.validate(); + result = bodyValidator.validate(fixtures.emptyStringJson); assert.equal(result.length, 0); }); }); @@ -178,14 +142,11 @@ describe('JsonExample', () => { describe('when key value is a null', () => { before(() => { - bodyValidator = new JsonExample( - '{"a":"a", "b": null}', - '{"a": "a","b": null }' - ); + bodyValidator = new JsonExample('{"a":"a", "b": null}'); }); describe('and i run validate()', () => { it("shouldn't return any errors", () => { - result = bodyValidator.validate(); + result = bodyValidator.validate('{"a": "a","b": null }'); assert.equal(result.length, 0); }); }); @@ -194,12 +155,12 @@ describe('JsonExample', () => { describe('when expected and real data are different on root level', () => { describe('when expected is object and real is array', () => { before(() => { - bodyValidator = new JsonExample('{"a":1}', '[{"a":1}]'); + bodyValidator = new JsonExample('{"a":1}'); }); describe('and i run validate()', () => { it('should not throw exception', () => { const fn = () => { - bodyValidator.validate(); + bodyValidator.validate('[{"a":1}]'); }; assert.doesNotThrow(fn); }); @@ -209,12 +170,12 @@ describe('JsonExample', () => { describe('when expected is array and real is object', () => { before(() => { - bodyValidator = new JsonExample('[{"a":1}]', '{"a":1}'); + bodyValidator = new JsonExample('[{"a":1}]'); }); describe('and i run validate()', () => { it('should not throw exception', () => { const fn = () => { - bodyValidator.validate(); + bodyValidator.validate('{"a":1}'); }; assert.doesNotThrow(fn); }); @@ -223,12 +184,12 @@ describe('JsonExample', () => { describe('when expected is primitive and real is object', () => { before(() => { - bodyValidator = new JsonExample('{"a":1}', '0'); + bodyValidator = new JsonExample('{"a":1}'); }); describe('and i run validate()', () => { it('should not throw exception', () => { const fn = () => { - bodyValidator.validate(); + bodyValidator.validate('0'); }; assert.doesNotThrow(fn); }); @@ -237,12 +198,12 @@ describe('JsonExample', () => { describe('when expected array and real is object', () => { before(() => { - bodyValidator = new JsonExample('{"a":1}', '[0,1,2]'); + bodyValidator = new JsonExample('{"a":1}'); }); describe('and i run validate()', () => { it('should not throw exception', () => { const fn = () => { - bodyValidator.validate(); + bodyValidator.validate('[0,1,2]'); }; assert.doesNotThrow(fn); }); @@ -251,25 +212,23 @@ describe('JsonExample', () => { describe('when real is empty object and expected is non-empty object', () => { before(() => { - bodyValidator = new JsonExample('{"a":1}', '{}'); + bodyValidator = new JsonExample('{"a":1}'); }); describe('and i run validate()', () => { it('should not throw exception', () => { const fn = () => { - bodyValidator.validate(); + bodyValidator.validate('{}'); }; assert.doesNotThrow(fn); }); }); it('should return 1 errors', () => { - result = bodyValidator.validate(); + result = bodyValidator.validate('{}'); assert.equal(result.length, 1); }); }); }); }); - - shared.shouldBehaveLikeAmandaToGavel(new JsonExample('{}', '{}')); }); diff --git a/test/unit/validators/json-schema.test.js b/test/unit/validators/json-schema.test.js index 584a74dc..5aeb5c2d 100644 --- a/test/unit/validators/json-schema.test.js +++ b/test/unit/validators/json-schema.test.js @@ -5,7 +5,6 @@ const { JsonSchema } = require('../../../lib/validators/json-schema'); const { ValidationErrors } = require('../../../lib/validators/validation-errors'); -const shared = require('../support/amanda-to-gavel-shared'); describe('JsonSchema', () => { let validator = null; From 549bc03951562194573e8fa36985118b6711f4a7 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 10:27:42 +0100 Subject: [PATCH 09/20] refactor: adjusts call signature of "TextDiff.validate()" --- test/unit/validators/text-diff.test.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/test/unit/validators/text-diff.test.js b/test/unit/validators/text-diff.test.js index 4a162af7..7e71be52 100644 --- a/test/unit/validators/text-diff.test.js +++ b/test/unit/validators/text-diff.test.js @@ -14,10 +14,8 @@ describe('TextDiff', () => { describe('when given non-string actual data', () => { it('should throw an exception', () => { - const fn = () => { - new TextDiff(''); - }; - expect(fn).to.throw(); + const validator = new TextDiff(''); + expect(validator.validate.bind(this, null)).to.throw(); }); }); @@ -26,12 +24,16 @@ describe('TextDiff', () => { it('should resolve on matching actual string', () => { const validator = new TextDiff(expected); - expect(validator.validate(expected)).to.be.true; + expect(validator.validate(expected)).to.deep.equal([]); }); it('should reject on non-matching actual string', () => { const validator = new TextDiff(expected); - expect(validator.validate('Nâtiônàl')).to.be.false; + expect(validator.validate('Nâtiônàl')).to.deep.equal([ + { + message: 'Actual and expected data do not match.' + } + ]); }); }); @@ -40,12 +42,16 @@ describe('TextDiff', () => { it('should resolve when given matching actual data', () => { const validator = new TextDiff(expected); - expect(validator.validate('john')).to.be.true; + expect(validator.validate('john')).to.deep.equal([]); }); it('should reject when given non-matching actual data', () => { const validator = new TextDiff(expected); - expect(validator.validate('barry')).to.be.false; + expect(validator.validate('barry')).to.deep.equal([ + { + message: 'Actual and expected data do not match.' + } + ]); }); }); From 03042273ced4d8e56cf10b5ccbffd964dab57f7d Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 10:38:01 +0100 Subject: [PATCH 10/20] refactor: fixes unsupported schema test suite for JsonSchemaValidator --- test/unit/validators/json-schema-next.test.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/test/unit/validators/json-schema-next.test.js b/test/unit/validators/json-schema-next.test.js index 20214dc1..f7219d01 100644 --- a/test/unit/validators/json-schema-next.test.js +++ b/test/unit/validators/json-schema-next.test.js @@ -17,10 +17,13 @@ describe('JSON Schema (next)', () => { let init; before(() => { - init = () => - new JsonSchemaValidator({ - $schema: 'http://json-schema.org/draft-02/schema' - }); + /* eslint-disable-next-line global-require */ + const validSchema = require('../../fixtures/invalid-schema-v3-v4.json'); + delete validSchema.$schema; + + init = () => { + return new JsonSchemaValidator(validSchema); + }; }); it('should throw an error about unsupported schema version', () => { From cd142fcb9792978af962d399dfe8c0359591d97a Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 11:15:16 +0100 Subject: [PATCH 11/20] refactor: Simplifies tv4 to headers coercion in HeadersJsonExample --- lib/validators/headers-json-example.js | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/lib/validators/headers-json-example.js b/lib/validators/headers-json-example.js index 0682779e..1b2aaa11 100644 --- a/lib/validators/headers-json-example.js +++ b/lib/validators/headers-json-example.js @@ -1,5 +1,3 @@ -const clone = require('clone'); - const errors = require('../errors'); const { JsonSchemaLegacy } = require('./json-schema-legacy'); const { @@ -69,20 +67,12 @@ class HeadersJsonExample extends JsonSchemaLegacy { const resolvedData = resolveHeaders(data); const results = super.validate(resolvedData); - if (results.length > 0) { - const resultCopy = clone(results, false); - - for (let i = 0; i < results.length; i++) { - resultCopy[i].message = tv4ToHeadersMessage( - resultCopy[i].message, - this.expected - ); - } - - return resultCopy; - } - - return results; + return results.map((result) => { + return { + ...result, + message: tv4ToHeadersMessage(result.message, this.expected) + }; + }); } } From d8a6e563b07e1b90169d207af54e61e9cae398ed Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 11:15:43 +0100 Subject: [PATCH 12/20] refactor: fixes the order of expected/actual values in custom chai assertions --- test/chai.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/chai.js b/test/chai.js index c8b43934..20271323 100644 --- a/test/chai.js +++ b/test/chai.js @@ -44,8 +44,8 @@ to have an error at index ${currentErrorIndex} that includes property "${propNam ${JSON.stringify(target)} `, - JSON.stringify(target), isRegExp ? expectedValue.toString() : JSON.stringify(expectedValue), + JSON.stringify(target), true ); }); From a74f2452d4911e016530a3c0ef24af7531ff92f4 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 11:17:05 +0100 Subject: [PATCH 13/20] refactor: removes the "json-ajv" test suite --- test/unit/validators/json-ajv.test.js | 79 --------------------------- 1 file changed, 79 deletions(-) delete mode 100644 test/unit/validators/json-ajv.test.js diff --git a/test/unit/validators/json-ajv.test.js b/test/unit/validators/json-ajv.test.js deleted file mode 100644 index bf5f694e..00000000 --- a/test/unit/validators/json-ajv.test.js +++ /dev/null @@ -1,79 +0,0 @@ -const { assert } = require('chai'); -const { JsonSchema } = require('../../../lib/validators/json-schema'); -const jsonSchema4 = require('../../fixtures/valid-schema-v4'); - -describe('JSON Schema (AJV)', () => { - describe('given JSON Schema Draft 4', () => { - describe('and the data is valid', () => { - let fn = null; - let validator; - - before(() => { - fn = () => { - validator = new JsonSchema(jsonSchema4, { - foo: 2, - bar: 'a' - }); - }; - }); - - it('should not throw any error', () => { - assert.doesNotThrow(fn); - }); - - it('should set @jsonSchemaVersion to v4', () => { - fn(); - assert.equal(validator.jsonSchemaVersion, 'v4'); - }); - - it('should not have any errors', () => { - assert.notProperty(validator, 'errors'); - }); - }); - - describe('and the data is invalid', () => { - let fn = null; - let validator; - - before(() => { - fn = () => { - validator = new JsonSchema(jsonSchema4, { - bar: 'a' - }); - validator.validate(); - }; - }); - - it('should not throw any error', () => { - assert.doesNotThrow(fn); - }); - - it('should set @jsonSchemaVersion to v4', () => { - fn(); - assert.equal(validator.jsonSchemaVersion, 'v4'); - }); - - describe('should return errors', () => { - it('should have exactly one error', () => { - assert.equal(validator.errors.length, 1); - }); - - it('should have a pointer', () => { - assert.propertyVal(validator.errors[0].location, 'pointer', '/foo'); - }); - - it('should have a property name', () => { - assert.propertyVal(validator.errors[0].location, 'property', 'foo'); - }); - - it('should have the error message about missing required property', () => { - assert.propertyVal( - validator.errors[0], - 'message', - `'foo' is a required property` - ); - }); - }); - }); - }); -}); From cf4952fbc8fab0b8316b27f72ff448e2be8da2ef Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 11:19:30 +0100 Subject: [PATCH 14/20] refactor: removes "JsonSchema" dependency from "json-example" test suite --- test/unit/validators/json-example.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/validators/json-example.test.js b/test/unit/validators/json-example.test.js index eed13699..258e0bcc 100644 --- a/test/unit/validators/json-example.test.js +++ b/test/unit/validators/json-example.test.js @@ -1,7 +1,6 @@ /* eslint-disable */ const { assert } = require('chai'); const { JsonExample } = require('../../../lib/validators/json-example'); -const { JsonSchema } = require('../../../lib/validators/json-schema'); const fixtures = require('../../fixtures'); describe('JsonExample', () => { From f33466ff2e3cfec1c7df39b7ad1c1f1902a1d7fd Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 11:53:50 +0100 Subject: [PATCH 15/20] test: adjusts JsonSchemaLegacy suite to assert unmatching value against valid DraftV4 --- .../validators/json-schema-legacy.test.js | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/test/unit/validators/json-schema-legacy.test.js b/test/unit/validators/json-schema-legacy.test.js index 1ee9cf84..479207a1 100644 --- a/test/unit/validators/json-schema-legacy.test.js +++ b/test/unit/validators/json-schema-legacy.test.js @@ -136,7 +136,7 @@ describe('JSON Schema (legacy)', () => { let errors; const data = { foo: 'should be number', - b: 'z' // DOES NOT RESPECT ENUM HERE. THINKS THIS IS VALID. + bar: 'z' }; before(() => { @@ -148,21 +148,42 @@ describe('JSON Schema (legacy)', () => { expect(errors).to.have.lengthOf(2); }); - it('should have an error message', () => { - expect(errors[0].message).to.equal( - `At '/foo' Invalid type: string (expected number)` - ); + describe('first error', () => { + it('should have an error message', () => { + expect(errors[0].message).to.equal( + `At '/foo' Invalid type: string (expected number)` + ); + }); + + it('should have a pointer', () => { + expect(errors[0]).to.have.nested.property( + 'location.pointer', + '/foo' + ); + }); + + it('should have a property name', () => { + expect(errors[0].location.property).to.deep.equal(['foo']); + }); }); - it('should have a pointer', () => { - expect(errors[0]).to.have.nested.property( - 'location.pointer', - '/foo' - ); - }); - - it('should have a property name', () => { - expect(errors[0].location.property).to.deep.equal(['foo']); + describe('second error', () => { + it('should have an error message', () => { + expect(errors[1].message).to.equal( + `At '/bar' No enum match for: "z"` + ); + }); + + it('should have a pointer', () => { + expect(errors[1]).to.have.nested.property( + 'location.pointer', + '/bar' + ); + }); + + it('should have a property name', () => { + expect(errors[1].location.property).to.deep.equal(['bar']); + }); }); }); }); From 75378593a4e5e344f6c869bdba7bf68b29b7dab5 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 14:27:05 +0100 Subject: [PATCH 16/20] feat: uses ["path", "array"] structure for "location.property" value --- lib/utils/to-gavel-result.js | 31 +++++++++ lib/validators/json-schema-legacy.js | 35 ++-------- test/unit/utils/to-gavel-result.test.js | 87 +++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 30 deletions(-) create mode 100644 lib/utils/to-gavel-result.js create mode 100644 test/unit/utils/to-gavel-result.test.js diff --git a/lib/utils/to-gavel-result.js b/lib/utils/to-gavel-result.js new file mode 100644 index 00000000..80c49240 --- /dev/null +++ b/lib/utils/to-gavel-result.js @@ -0,0 +1,31 @@ +const jsonPointer = require('json-pointer'); + +function splitProperty(property) { + return property.split(/\.|\[|\]/).filter(Boolean); +} + +function reduceProperties(acc, property) { + return acc.concat(splitProperty(property)); +} + +/** + * Converts legacy (Amanda/TV4) error messages + * to the Gavel-compliant structure. + */ +function toGavelResult(legacyErrors) { + return Array.from({ length: legacyErrors.length }, (_, index) => { + const item = legacyErrors[index]; + const propertyPath = item.property.reduce(reduceProperties, []); + const pointer = jsonPointer.compile(propertyPath); + + return { + message: item.message, + location: { + pointer, + property: propertyPath + } + }; + }); +} + +module.exports = toGavelResult; diff --git a/lib/validators/json-schema-legacy.js b/lib/validators/json-schema-legacy.js index baab4ec8..d54dc9ca 100644 --- a/lib/validators/json-schema-legacy.js +++ b/lib/validators/json-schema-legacy.js @@ -4,6 +4,7 @@ const jsonPointer = require('json-pointer'); const { JsonSchemaValidator, META_SCHEMA } = require('./json-schema-next'); const { ValidationErrors } = require('./validation-errors'); +const toGavelResult = require('../utils/to-gavel-result'); /** * Returns a proper article for a given string. @@ -103,12 +104,12 @@ class JsonSchemaLegacy extends JsonSchemaValidator { errors = new ValidationErrors(error); } }); - } catch (error) { + } catch (internalError) { errors = new ValidationErrors({ '0': { property: [], attributeValue: true, - message: `Validator internal error: ${error.message}`, + message: `Validator internal error: ${internalError.message}`, validatorName: 'error' }, length: 1, @@ -116,7 +117,7 @@ class JsonSchemaLegacy extends JsonSchemaValidator { }); } - return this.toGavelResult(errors); + return toGavelResult(errors); } validateUsingTV4(data) { @@ -154,33 +155,7 @@ class JsonSchemaLegacy extends JsonSchemaValidator { } const errors = new ValidationErrors(amandaCompatibleError); - return this.toGavelResult(errors); - } - - /** - * Converts Amanda-like validation result to the - * unified Gavel public validation result. - */ - toGavelResult(amandaLikeResult) { - const results = Array.from( - { length: amandaLikeResult.length }, - (_, index) => { - const item = amandaLikeResult[index]; - const { property, message } = item; - const pathArray = [].concat(property).filter(Boolean); - const pointer = jsonPointer.compile(pathArray); - - return { - message, - location: { - pointer, - property - } - }; - } - ); - - return results; + return toGavelResult(errors); } } diff --git a/test/unit/utils/to-gavel-result.test.js b/test/unit/utils/to-gavel-result.test.js new file mode 100644 index 00000000..69c539e8 --- /dev/null +++ b/test/unit/utils/to-gavel-result.test.js @@ -0,0 +1,87 @@ +const { expect } = require('chai'); +const toGavelResult = require('../../../lib/utils/to-gavel-result'); + +describe('toGavelResult', () => { + // Currently TV4 output is coerced to Amanda format. + // Then Amanda format is coerced to Gavel public API. + describe('given Amanda errors', () => { + let coercedErrors; + + before(() => { + coercedErrors = toGavelResult({ + length: 2, + 0: { + property: ['users', 'username'], + propertyValue: 123, + attributeName: 'type', + attributeValue: 'string', + message: 'Amanda error message' + }, + 1: { + property: ['friends[2]', 'online'], + propertyValue: false, + attributeName: 'type', + attributeValue: 'boolean', + message: 'Arbitrary error message about "online"' + } + }); + }); + + describe('given coerced to Gavel-compliant error', () => { + it('should return 2 errors', () => { + expect(coercedErrors).to.have.lengthOf(2); + }); + + describe('given in-object error', () => { + it('should preserve the original error message', () => { + expect(coercedErrors[0]).to.have.property( + 'message', + 'Amanda error message' + ); + }); + + describe('should produce "location" property', () => { + it('should have "pointer"', () => { + expect(coercedErrors[0]).to.have.nested.property( + 'location.pointer', + '/users/username' + ); + }); + + it('should have "property"', () => { + expect(coercedErrors[0].location.property).to.deep.equal([ + 'users', + 'username' + ]); + }); + }); + }); + + describe('given in-array error', () => { + it('should preserve the original error message', () => { + expect(coercedErrors[1]).to.have.property( + 'message', + 'Arbitrary error message about "online"' + ); + }); + + describe('should produce "location" property', () => { + it('should have "pointer"', () => { + expect(coercedErrors[1]).to.have.nested.property( + 'location.pointer', + '/friends/2/online' + ); + }); + + it('should have "property"', () => { + expect(coercedErrors[1].location.property).to.deep.equal([ + 'friends', + '2', + 'online' + ]); + }); + }); + }); + }); + }); +}); From 62237205fc080090e5447b76547884212016c6c6 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 14:49:24 +0100 Subject: [PATCH 17/20] chore: installs "@rollup/plugin-json" --- package-lock.json | 9 +++++++++ package.json | 1 + 2 files changed, 10 insertions(+) diff --git a/package-lock.json b/package-lock.json index 9fe5fc90..5f47e9c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -126,6 +126,15 @@ } } }, + "@rollup/plugin-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.0.0.tgz", + "integrity": "sha512-Z65CtEVWv40+ri4CvmswyhtuUtki9yP5p0UJN/GyCKKyU4jRuDS9CG0ZuV7/XuS7zGkoajyE7E4XBEaC4GW62A==", + "dev": true, + "requires": { + "rollup-pluginutils": "^2.5.0" + } + }, "@samverschueren/stream-to-observable": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", diff --git a/package.json b/package.json index 9b4dbef1..aac04007 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "url": "0.11.0" }, "devDependencies": { + "@rollup/plugin-json": "4.0.0", "chai": "4.2.0", "cross-spawn": "7.0.1", "cucumber": "1.3.2", From 75650c2fcd4ed8df289ab4be9e978ccaa96c438b Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 14:50:01 +0100 Subject: [PATCH 18/20] chore: uses "@rollup/plugin-json" to import ".json" modules --- rollup.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rollup.config.js b/rollup.config.js index 3df08872..a6f80f76 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,5 +1,6 @@ const resolve = require('rollup-plugin-node-resolve'); const commonjs = require('rollup-plugin-commonjs'); +const json = require('@rollup/plugin-json/dist'); const packageJson = require('./package.json'); const buildUmd = { @@ -19,6 +20,7 @@ const buildUmd = { // Throw when such modules are present in the bundle. preferBuiltins: false }), + json(), commonjs() ] }; From 9bccf124f99f8f8053ee421f5608e90245d7acb1 Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Mon, 2 Dec 2019 15:42:29 +0100 Subject: [PATCH 19/20] refactor: uses raw TV4 error format for header-related error messages --- lib/validators/headers-json-example.js | 13 +- lib/validators/json-example.js | 7 - lib/validators/json-schema-next.js | 1 - package-lock.json | 1613 +++++++++-------- .../unit/utils/tv4-to-headers-message.test.js | 2 +- .../headers-json-example-validator.test.js | 8 +- 6 files changed, 828 insertions(+), 816 deletions(-) diff --git a/lib/validators/headers-json-example.js b/lib/validators/headers-json-example.js index 1b2aaa11..42d56b76 100644 --- a/lib/validators/headers-json-example.js +++ b/lib/validators/headers-json-example.js @@ -4,7 +4,6 @@ const { SchemaV4Generator, SchemaV4Properties } = require('../utils/schema-v4-generator'); -const tv4ToHeadersMessage = require('../utils/tv4-to-headers-message'); const resolveHeaders = (headers) => { if (typeof headers !== 'object') { @@ -67,12 +66,12 @@ class HeadersJsonExample extends JsonSchemaLegacy { const resolvedData = resolveHeaders(data); const results = super.validate(resolvedData); - return results.map((result) => { - return { - ...result, - message: tv4ToHeadersMessage(result.message, this.expected) - }; - }); + /** + * @TODO Revert custom formatting of TV4 header-related validation errors. + * @see https://github.com/apiaryio/gavel.js/issues/360 + * @see https://github.com/apiaryio/gavel.js/blob/816b7ab1fb8fec345f842e93edc214a532758323/lib/validators/headers-json-example.js#L76-L81 + */ + return results; } } diff --git a/lib/validators/json-example.js b/lib/validators/json-example.js index 0739bed9..de18944c 100644 --- a/lib/validators/json-example.js +++ b/lib/validators/json-example.js @@ -28,13 +28,6 @@ class JsonExample extends JsonSchema { validate(actual) { const { jsonSchema: expected } = this; - console.log( - 'JsonExample: Validating', - JSON.stringify(actual, null, 2), - 'against', - JSON.stringify(expected, null, 2) - ); - if (typeof actual !== 'string') { const outError = new errors.MalformedDataError( 'JsonExample validator: provided actual data is not string' diff --git a/lib/validators/json-schema-next.js b/lib/validators/json-schema-next.js index 028690e5..6f350599 100644 --- a/lib/validators/json-schema-next.js +++ b/lib/validators/json-schema-next.js @@ -115,7 +115,6 @@ class JsonSchemaValidator { try { resolvedData = parseJson(data); } catch (error) { - console.log('failed json', data); const dataError = new errors.DataNotJsonParsableError( `Expected data to be a valid JSON, but got: ${data}. ${error.message}` ); diff --git a/package-lock.json b/package-lock.json index 5f47e9c4..07858453 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,18 +5,18 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", "dev": true, "requires": { "@babel/highlight": "^7.0.0" } }, "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", "dev": true, "requires": { "chalk": "^2.0.0", @@ -25,53 +25,51 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz", - "integrity": "sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.1", + "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" - }, - "dependencies": { - "@nodelib/fs.stat": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz", - "integrity": "sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw==", - "dev": true - } } }, + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, "@nodelib/fs.walk": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz", - "integrity": "sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.1", + "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" } }, "@octokit/endpoint": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.0.tgz", - "integrity": "sha512-TXYS6zXeBImNB9BVj+LneMDqXX+H0exkOpyXobvp92O3B1348QsKnNioISFKgOMsb3ibZvQGwCdpiwQd3KAjIA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.1.tgz", + "integrity": "sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==", "dev": true, "requires": { - "@octokit/types": "^1.0.0", + "@octokit/types": "^2.0.0", "is-plain-object": "^3.0.0", "universal-user-agent": "^4.0.0" } }, "@octokit/request": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.0.tgz", - "integrity": "sha512-mMIeNrtYyNEIYNsKivDyUAukBkw0M5ckyJX56xoFRXSasDPCloIXaQOnaKNopzQ8dIOvpdq1ma8gmrS+h6O2OQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.1.tgz", + "integrity": "sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==", "dev": true, "requires": { "@octokit/endpoint": "^5.5.0", "@octokit/request-error": "^1.0.1", - "@octokit/types": "^1.0.0", + "@octokit/types": "^2.0.0", "deprecation": "^2.0.0", "is-plain-object": "^3.0.0", "node-fetch": "^2.3.0", @@ -80,19 +78,20 @@ } }, "@octokit/request-error": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.0.4.tgz", - "integrity": "sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.0.tgz", + "integrity": "sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==", "dev": true, "requires": { + "@octokit/types": "^2.0.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "@octokit/rest": { - "version": "16.34.0", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.34.0.tgz", - "integrity": "sha512-EBe5qMQQOZRuezahWCXCnSe0J6tAqrW2hrEH9U8esXzKor1+HUDf8jgImaZf5lkTyWCQA296x9kAH5c0pxEgVQ==", + "version": "16.35.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.35.0.tgz", + "integrity": "sha512-9ShFqYWo0CLoGYhA1FdtdykJuMzS/9H6vSbbQWDX4pWr4p9v+15MsH/wpd/3fIU+tSxylaNO48+PIHqOkBRx3w==", "dev": true, "requires": { "@octokit/request": "^5.2.0", @@ -110,20 +109,12 @@ } }, "@octokit/types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-1.1.0.tgz", - "integrity": "sha512-t4ZD74UnNVMq6kZBDZceflRKK3q4o5PoCKMAGht0RK84W57tqonqKL3vCxJHtbGExdan9RwV8r7VJBZxIM1O7Q==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.0.2.tgz", + "integrity": "sha512-StASIL2lgT3TRjxv17z9pAqbnI7HGu9DrJlg3sEBFfCLaMEqp+O3IQPUF6EZtQ4xkAu2ml6kMBBCtGxjvmtmuQ==", "dev": true, "requires": { - "@types/node": "^12.11.1" - }, - "dependencies": { - "@types/node": { - "version": "12.11.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.7.tgz", - "integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==", - "dev": true - } + "@types/node": ">= 8" } }, "@rollup/plugin-json": { @@ -145,14 +136,14 @@ } }, "@semantic-release/commit-analyzer": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-6.3.1.tgz", - "integrity": "sha512-TQj/BU48b6dy1jS4yJ2Vfd7vOwkNWM/ySuISvW97yeQDd8Lm++t/NUlLdsn6+IZmtGZGMwsfGHYBZSLMuRZmQQ==", + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-6.3.3.tgz", + "integrity": "sha512-Pyv1ZL2u5AIOY4YbxFCAB5J1PEh5yON8ylbfiPiriDGGW6Uu1U3Y8lysMtWu+FUD5x7tSnyIzhqx0+fxPxqbgw==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", "conventional-commits-filter": "^2.0.0", - "conventional-commits-parser": "^3.0.0", + "conventional-commits-parser": "^3.0.7", "debug": "^4.0.0", "import-from": "^3.0.0", "lodash": "^4.17.4" @@ -189,9 +180,9 @@ } }, "@semantic-release/npm": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-5.3.2.tgz", - "integrity": "sha512-4uE4pYvf5XEWqJPTLCrrmp5zu9XnnLqDjsn+2yrpMICNCpTq3M5g9OD7hwQoolg5v373t2ZnNgdcjsz+lqU0aA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-5.3.4.tgz", + "integrity": "sha512-XjITNRA/oOpJ7BfHk/WaOHs1WniYBszTde/bwADjjk1Luacpxg87jbDQVVt/oA3Zlx+MelxACRIEuRiPC5gu8g==", "dev": true, "requires": { "@semantic-release/error": "^2.2.0", @@ -209,9 +200,9 @@ }, "dependencies": { "execa": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-3.2.0.tgz", - "integrity": "sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz", + "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==", "dev": true, "requires": { "cross-spawn": "^7.0.0", @@ -241,12 +232,6 @@ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, "npm-run-path": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.0.tgz", @@ -274,12 +259,6 @@ "lines-and-columns": "^1.1.6" } }, - "path-key": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", - "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", - "dev": true - }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -291,13 +270,19 @@ "parse-json": "^5.0.0", "type-fest": "^0.6.0" } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true } } }, "@semantic-release/release-notes-generator": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-7.3.2.tgz", - "integrity": "sha512-vYGydZPoQqL4aJOsaqXTZIekRb3aa/OlxlEVUvyrWWlNGqmQ1T7NUOos9eoN5DBCEuk6PwDrxPbhzgswxcvprQ==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-7.3.5.tgz", + "integrity": "sha512-LGjgPBGjjmjap/76O0Md3wc04Y7IlLnzZceLsAkcYRwGQdRPTTFUJKqDQTuieWTs7zfHzQoZqsqPfFxEN+g2+Q==", "dev": true, "requires": { "conventional-changelog-angular": "^5.0.0", @@ -412,12 +397,6 @@ "read-pkg": "^5.2.0", "type-fest": "^0.8.1" } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true } } }, @@ -431,9 +410,9 @@ } }, "@sinonjs/formatio": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.1.tgz", - "integrity": "sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", + "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", "dev": true, "requires": { "@sinonjs/commons": "^1", @@ -449,14 +428,6 @@ "@sinonjs/commons": "^1.3.0", "array-from": "^2.1.1", "lodash": "^4.17.15" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } } }, "@sinonjs/text-encoding": { @@ -466,9 +437,9 @@ "dev": true }, "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.40.tgz", + "integrity": "sha512-p3KZgMto/JyxosKGmnLDJ/dG5wf+qTRMUjHJcspC2oQKa4jP7mz+tv0ND56lLBu3ojHlhzY33Ol+khLyNmilkA==", "dev": true }, "@types/events": { @@ -495,9 +466,9 @@ "dev": true }, "@types/node": { - "version": "12.0.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.10.tgz", - "integrity": "sha512-LcsGbPomWsad6wmMNv7nBLw7YYYyfdYcz6xryKYQhx89c3XXan+8Q6AJ43G5XDIaklaVkK3mE4fCb0SBvMiPSQ==", + "version": "12.12.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.14.tgz", + "integrity": "sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA==", "dev": true }, "@types/normalize-package-data": { @@ -553,13 +524,13 @@ } }, "aggregate-error": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.0.tgz", - "integrity": "sha512-yKD9kEoJIR+2IFqhMwayIBgheLYbB3PS2OBhWae1L/ODTd/JF/30cW0bc9TqzRL3k4U41Dieu3BF4I29p8xesA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", "dev": true, "requires": { "clean-stack": "^2.0.0", - "indent-string": "^3.2.0" + "indent-string": "^4.0.0" } }, "ajv": { @@ -585,15 +556,18 @@ "dev": true }, "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "ansi-styles": { @@ -665,10 +639,10 @@ "es-abstract": "^1.7.0" } }, - "array-uniq": { + "array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-2.1.0.tgz", - "integrity": "sha512-bdHxtev7FN6+MXI1YFW0Q8mQ8dTJc2S8AMfju+ZR77pbg2yAdVyDlwkaUI7Har0LyOMRFPHrJ9lYdyjZZswdlQ==", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, "arrify": { @@ -882,12 +856,12 @@ "dev": true }, "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "^3.1.0" } }, "cli-table": { @@ -977,10 +951,16 @@ "wrap-ansi": "^5.1.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "string-width": { @@ -994,15 +974,6 @@ "strip-ansi": "^5.1.0" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -1049,9 +1020,9 @@ "dev": true }, "colors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true }, "commander": { @@ -1076,9 +1047,9 @@ "dev": true }, "confusing-browser-globals": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.7.tgz", - "integrity": "sha512-cgHI1azax5ATrZ8rJ+ODDML9Fvu67PimB6aNxBrc/QwSaDaM9eTfIEUHx3bBLJJ82ioSb+/5zfsMCCEJax3ByQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", + "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", "dev": true }, "contains-path": { @@ -1093,9 +1064,9 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "conventional-changelog-angular": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.5.tgz", - "integrity": "sha512-RrkdWnL/TVyWV1ayWmSsrWorsTDqjL/VwG5ZSEneBQrd65ONcfeA1cW7FLtNweQyMiKOyriCMTKRSlk18DjTrw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz", + "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -1103,9 +1074,9 @@ } }, "conventional-changelog-writer": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.9.tgz", - "integrity": "sha512-2Y3QfiAM37WvDMjkVNaRtZgxVzWKj73HE61YQ/95T53yle+CRwTVSl6Gbv/lWVKXeZcM5af9n9TDVf0k7Xh+cw==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz", + "integrity": "sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -1113,19 +1084,11 @@ "dateformat": "^3.0.0", "handlebars": "^4.4.0", "json-stringify-safe": "^5.0.1", - "lodash": "^4.2.1", - "meow": "^4.0.0", + "lodash": "^4.17.15", + "meow": "^5.0.0", "semver": "^6.0.0", "split": "^1.0.0", "through2": "^3.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } } }, "conventional-commits-filter": { @@ -1139,15 +1102,15 @@ } }, "conventional-commits-parser": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.5.tgz", - "integrity": "sha512-qVz9+5JwdJzsbt7JbJ6P7NOXBGt8CyLFJYSjKAuPSgO+5UGfcsbk9EMR+lI8Unlvx6qwIc2YDJlrGIfay2ehNA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz", + "integrity": "sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ==", "dev": true, "requires": { "JSONStream": "^1.0.4", - "is-text-path": "^2.0.0", - "lodash": "^4.2.1", - "meow": "^4.0.0", + "is-text-path": "^1.0.1", + "lodash": "^4.17.15", + "meow": "^5.0.0", "split2": "^2.0.0", "through2": "^3.0.0", "trim-off-newlines": "^1.0.0" @@ -1208,38 +1171,6 @@ "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" - }, - "dependencies": { - "path-key": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", - "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "which": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz", - "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } } }, "crypto-random-string": { @@ -1270,9 +1201,9 @@ }, "dependencies": { "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true } } @@ -1422,21 +1353,6 @@ "slash": "^3.0.0" }, "dependencies": { - "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true - }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, "rimraf": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", @@ -1521,15 +1437,15 @@ "dev": true }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "requires": { "once": "^1.4.0" @@ -1546,9 +1462,9 @@ }, "dependencies": { "execa": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-3.2.0.tgz", - "integrity": "sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz", + "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==", "dev": true, "requires": { "cross-spawn": "^7.0.0", @@ -1592,12 +1508,6 @@ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==", "dev": true - }, - "path-key": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", - "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", - "dev": true } } }, @@ -1620,23 +1530,27 @@ } }, "es-abstract": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", - "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.2.tgz", + "integrity": "sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA==", "dev": true, "requires": { - "es-to-primitive": "^1.2.0", + "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "has": "^1.0.3", + "has-symbols": "^1.0.1", "is-callable": "^1.1.4", "is-regex": "^1.0.4", - "object-keys": "^1.0.12" + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" } }, "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { "is-callable": "^1.1.4", @@ -1645,14 +1559,14 @@ } }, "es5-ext": { - "version": "0.10.50", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", - "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", "dev": true, "requires": { "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.1", - "next-tick": "^1.0.0" + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" } }, "es6-iterator": { @@ -1682,13 +1596,13 @@ } }, "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { - "d": "1", - "es5-ext": "~0.10.14" + "d": "^1.0.1", + "ext": "^1.1.2" } }, "escape-string-regexp": { @@ -1742,12 +1656,6 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -1769,26 +1677,35 @@ } } }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "shebang-regex": "^1.0.0" } }, - "strip-json-comments": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", - "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, @@ -1996,9 +1913,9 @@ "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "execa": { @@ -2028,6 +1945,59 @@ "shebang-command": "^1.2.0", "which": "^1.2.9" } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", + "dev": true } } }, @@ -2047,6 +2017,19 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, + "fast-glob": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz", + "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2" + } + }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", @@ -2105,12 +2088,11 @@ } }, "find-versions": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.1.0.tgz", - "integrity": "sha512-NCTfNiVzeE/xL+roNDffGuRbrWI6atI18lTJ22vKp7rs2OhYzMK3W1dIdO2TUndH/QMcacM4d1uWwgcZcHK69Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", + "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", "dev": true, "requires": { - "array-uniq": "^2.1.0", "semver-regex": "^2.0.0" } }, @@ -2164,14 +2146,6 @@ "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - } } }, "fs.realpath": { @@ -2272,9 +2246,9 @@ } }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -2316,111 +2290,18 @@ "slash": "^3.0.0" }, "dependencies": { - "@nodelib/fs.stat": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz", - "integrity": "sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "fast-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.0.4.tgz", - "integrity": "sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.1", - "@nodelib/fs.walk": "^1.2.1", - "glob-parent": "^5.0.0", - "is-glob": "^4.0.1", - "merge2": "^1.2.3", - "micromatch": "^4.0.2" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", - "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, "ignore": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.2.tgz", - "integrity": "sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "graceful-fs": { - "version": "4.1.15", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", - "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, "growl": { @@ -2430,9 +2311,9 @@ "dev": true }, "handlebars": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", - "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz", + "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==", "dev": true, "requires": { "neo-async": "^2.6.0", @@ -2481,9 +2362,9 @@ "dev": true }, "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, "he": { @@ -2499,9 +2380,9 @@ "dev": true }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", "dev": true }, "http-proxy-agent": { @@ -2669,6 +2550,12 @@ "parse-json": "^5.0.0", "type-fest": "^0.6.0" } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true } } }, @@ -2688,9 +2575,9 @@ "dev": true }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -2721,9 +2608,9 @@ "dev": true }, "indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, "inflight": { @@ -2737,9 +2624,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "ini": { @@ -2769,36 +2656,6 @@ "through": "^2.3.6" }, "dependencies": { - "ansi-escapes": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", - "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", - "dev": true, - "requires": { - "type-fest": "^0.5.2" - } - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "figures": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", @@ -2807,54 +2664,6 @@ "requires": { "escape-string-regexp": "^1.0.5" } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "string-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", - "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^5.2.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "type-fest": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", - "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", - "dev": true } } }, @@ -2909,9 +2718,9 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "is-generator": { @@ -2990,12 +2799,20 @@ "dev": true }, "is-reference": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.3.tgz", - "integrity": "sha512-W1iHHv/oyBb2pPxkBxtaewxa1BC58Pn5J0hogyCdefwUIvb6R+TGbAcIa4qPNYLqLhb3EnOgUf2MQkkF76BcKw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", + "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", "dev": true, "requires": { "@types/estree": "0.0.39" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + } } }, "is-regex": { @@ -3019,21 +2836,21 @@ "dev": true }, "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "has-symbols": "^1.0.0" + "has-symbols": "^1.0.1" } }, "is-text-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", "dev": true, "requires": { - "text-extensions": "^2.0.0" + "text-extensions": "^1.0.0" } }, "isarray": { @@ -3180,31 +2997,18 @@ }, "dependencies": { "commander": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz", - "integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==", + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, "execa": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/execa/-/execa-2.0.5.tgz", - "integrity": "sha512-SwmwZZyJjflcqLSgllk4EQlMLst2p9muyzwNugKGFlpAz6rZ7M+s2nBR97GAq4Vzjwx2y9rcMcmqzojwN+xwNA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-2.1.0.tgz", + "integrity": "sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw==", "dev": true, "requires": { - "cross-spawn": "^6.0.5", + "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", @@ -3230,15 +3034,6 @@ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", "dev": true }, - "log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2" - } - }, "npm-run-path": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-3.1.0.tgz", @@ -3246,14 +3041,6 @@ "dev": true, "requires": { "path-key": "^3.0.0" - }, - "dependencies": { - "path-key": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", - "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", - "dev": true - } } }, "p-finally": { @@ -3279,6 +3066,14 @@ "listr-verbose-renderer": "^0.5.0", "p-map": "^2.0.0", "rxjs": "^6.3.3" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } } }, "listr-silent-renderer": { @@ -3328,6 +3123,12 @@ "supports-color": "^2.0.0" } }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, "log-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", @@ -3366,6 +3167,15 @@ "figures": "^2.0.0" }, "dependencies": { + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -3374,6 +3184,31 @@ "requires": { "escape-string-regexp": "^1.0.5" } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } } } }, @@ -3400,9 +3235,9 @@ } }, "lodash": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==", + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, "lodash.capitalize": { @@ -3466,12 +3301,12 @@ "dev": true }, "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, "requires": { - "chalk": "^2.0.1" + "chalk": "^2.4.2" } }, "log-update": { @@ -3483,6 +3318,48 @@ "ansi-escapes": "^3.0.0", "cli-cursor": "^2.0.0", "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + } } }, "lolex": { @@ -3523,9 +3400,9 @@ "dev": true }, "magic-string": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz", - "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz", + "integrity": "sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==", "dev": true, "requires": { "sourcemap-codec": "^1.4.4" @@ -3555,6 +3432,14 @@ "cli-table": "^0.3.1", "node-emoji": "^1.4.1", "supports-hyperlinks": "^1.0.1" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + } } }, "media-typer": { @@ -3563,22 +3448,28 @@ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" }, "meow": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", - "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", "dev": true, "requires": { "camelcase-keys": "^4.0.0", "decamelize-keys": "^1.0.0", "loud-rejection": "^1.0.0", - "minimist": "^1.1.3", "minimist-options": "^3.0.1", "normalize-package-data": "^2.3.4", "read-pkg-up": "^3.0.0", "redent": "^2.0.0", - "trim-newlines": "^2.0.0" + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" }, "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -3636,6 +3527,15 @@ "find-up": "^2.0.0", "read-pkg": "^3.0.0" } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } } } }, @@ -3646,9 +3546,9 @@ "dev": true }, "merge2": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", - "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", "dev": true }, "micromatch": { @@ -3683,9 +3583,9 @@ } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "minimist-options": { @@ -3705,14 +3605,6 @@ "dev": true, "requires": { "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } } }, "mocha": { @@ -3788,6 +3680,15 @@ "path-exists": "^3.0.0" } }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -3818,6 +3719,12 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, "supports-color": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", @@ -3826,6 +3733,15 @@ "requires": { "has-flag": "^3.0.0" } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } } } }, @@ -3916,6 +3832,14 @@ "requires": { "object.getownpropertydescriptors": "^2.0.3", "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "node-fetch": { @@ -3934,6 +3858,14 @@ "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } } }, "normalize-path": { @@ -3949,9 +3881,9 @@ "dev": true }, "npm": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.12.0.tgz", - "integrity": "sha512-juj5VkB3/k+PWbJUnXD7A/8oc8zLusDnK/sV9PybSalsbOVOTIp5vSE0rz5rQ7BsmUgQS47f/L2GYQnWXaKgnQ==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.13.1.tgz", + "integrity": "sha512-2awiDZ9JuV/UoF4oXGhekCURC2X+eLLRz9/e58AGrPDlpzyn7e4oCaZmkzyEaisxM7jSoFKNnZhzB4xbmbM0Yw==", "dev": true, "requires": { "JSONStream": "^1.3.5", @@ -3965,7 +3897,7 @@ "byte-size": "^5.0.1", "cacache": "^12.0.3", "call-limit": "^1.1.1", - "chownr": "^1.1.2", + "chownr": "^1.1.3", "ci-info": "^2.0.0", "cli-columns": "^3.1.2", "cli-table3": "^0.5.1", @@ -3983,7 +3915,7 @@ "fs-write-stream-atomic": "~1.0.10", "gentle-fs": "^2.2.1", "glob": "^7.1.4", - "graceful-fs": "^4.2.2", + "graceful-fs": "^4.2.3", "has-unicode": "~2.0.1", "hosted-git-info": "^2.8.5", "iferr": "^1.0.2", @@ -3996,7 +3928,7 @@ "is-cidr": "^3.0.0", "json-parse-better-errors": "^1.0.2", "lazy-property": "~1.0.0", - "libcipm": "^4.0.4", + "libcipm": "^4.0.7", "libnpm": "^3.0.1", "libnpmaccess": "^3.0.2", "libnpmhook": "^5.0.3", @@ -4030,23 +3962,23 @@ "npm-install-checks": "^3.0.2", "npm-lifecycle": "^3.1.4", "npm-package-arg": "^6.1.1", - "npm-packlist": "^1.4.4", + "npm-packlist": "^1.4.6", "npm-pick-manifest": "^3.0.2", "npm-profile": "^4.0.2", - "npm-registry-fetch": "^4.0.0", + "npm-registry-fetch": "^4.0.2", "npm-user-validate": "~1.0.0", "npmlog": "~4.1.2", "once": "~1.4.0", "opener": "^1.5.1", "osenv": "^0.1.5", - "pacote": "^9.5.8", + "pacote": "^9.5.9", "path-is-inside": "~1.0.2", "promise-inflight": "~1.0.1", "qrcode-terminal": "^0.12.0", "query-string": "^6.8.2", "qw": "~1.0.1", "read": "~1.0.7", - "read-cmd-shim": "^1.0.4", + "read-cmd-shim": "^1.0.5", "read-installed": "~4.0.3", "read-package-json": "^2.1.0", "read-package-tree": "^5.3.1", @@ -4063,7 +3995,7 @@ "sorted-union-stream": "~2.1.3", "ssri": "^6.0.1", "stringify-package": "^1.0.1", - "tar": "^4.4.12", + "tar": "^4.4.13", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "uid-number": "0.0.6", @@ -4071,7 +4003,7 @@ "unique-filename": "^1.1.1", "unpipe": "~1.0.0", "update-notifier": "^2.5.0", - "uuid": "^3.3.2", + "uuid": "^3.3.3", "validate-npm-package-license": "^3.0.4", "validate-npm-package-name": "~3.0.0", "which": "^1.3.1", @@ -4354,7 +4286,7 @@ } }, "chownr": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true }, @@ -5000,7 +4932,7 @@ }, "dependencies": { "minipass": { - "version": "2.8.6", + "version": "2.9.0", "bundled": true, "dev": true, "requires": { @@ -5204,7 +5136,7 @@ } }, "graceful-fs": { - "version": "4.2.2", + "version": "4.2.3", "bundled": true, "dev": true }, @@ -5275,7 +5207,7 @@ } }, "https-proxy-agent": { - "version": "2.2.2", + "version": "2.2.4", "bundled": true, "dev": true, "requires": { @@ -5305,7 +5237,7 @@ "dev": true }, "ignore-walk": { - "version": "3.0.1", + "version": "3.0.3", "bundled": true, "dev": true, "requires": { @@ -5559,7 +5491,7 @@ } }, "libcipm": { - "version": "4.0.4", + "version": "4.0.7", "bundled": true, "dev": true, "requires": { @@ -5862,7 +5794,7 @@ } }, "make-fetch-happen": { - "version": "5.0.0", + "version": "5.0.2", "bundled": true, "dev": true, "requires": { @@ -5870,7 +5802,7 @@ "cacache": "^12.0.0", "http-cache-semantics": "^3.8.1", "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.1", + "https-proxy-agent": "^2.2.3", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "node-fetch-npm": "^2.0.2", @@ -5923,30 +5855,25 @@ "bundled": true, "dev": true }, - "minipass": { - "version": "2.3.3", + "minizlib": { + "version": "1.3.3", "bundled": true, "dev": true, "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "minipass": "^2.9.0" }, "dependencies": { - "yallist": { - "version": "3.0.2", + "minipass": { + "version": "2.9.0", "bundled": true, - "dev": true + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } } } }, - "minizlib": { - "version": "1.2.2", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^2.2.1" - } - }, "mississippi": { "version": "3.0.0", "bundled": true, @@ -6134,7 +6061,7 @@ } }, "npm-packlist": { - "version": "1.4.4", + "version": "1.4.6", "bundled": true, "dev": true, "requires": { @@ -6163,7 +6090,7 @@ } }, "npm-registry-fetch": { - "version": "4.0.0", + "version": "4.0.2", "bundled": true, "dev": true, "requires": { @@ -6172,7 +6099,15 @@ "figgy-pudding": "^3.4.1", "lru-cache": "^5.1.1", "make-fetch-happen": "^5.0.0", - "npm-package-arg": "^6.1.0" + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "bundled": true, + "dev": true + } } }, "npm-run-path": { @@ -6308,7 +6243,7 @@ } }, "pacote": { - "version": "9.5.8", + "version": "9.5.9", "bundled": true, "dev": true, "requires": { @@ -6344,7 +6279,7 @@ }, "dependencies": { "minipass": { - "version": "2.3.5", + "version": "2.9.0", "bundled": true, "dev": true, "requires": { @@ -6577,7 +6512,7 @@ } }, "read-cmd-shim": { - "version": "1.0.4", + "version": "1.0.5", "bundled": true, "dev": true, "requires": { @@ -6793,17 +6728,17 @@ "dev": true }, "smart-buffer": { - "version": "4.0.2", + "version": "4.1.0", "bundled": true, "dev": true }, "socks": { - "version": "2.3.2", + "version": "2.3.3", "bundled": true, "dev": true, "requires": { - "ip": "^1.1.5", - "smart-buffer": "4.0.2" + "ip": "1.1.5", + "smart-buffer": "^4.1.0" } }, "socks-proxy-agent": { @@ -7049,7 +6984,7 @@ } }, "tar": { - "version": "4.4.12", + "version": "4.4.13", "bundled": true, "dev": true, "requires": { @@ -7063,7 +6998,7 @@ }, "dependencies": { "minipass": { - "version": "2.8.6", + "version": "2.9.0", "bundled": true, "dev": true, "requires": { @@ -7250,7 +7185,7 @@ } }, "uuid": { - "version": "3.3.2", + "version": "3.3.3", "bundled": true, "dev": true }, @@ -7437,6 +7372,14 @@ "dev": true, "requires": { "path-key": "^2.0.0" + }, + "dependencies": { + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + } } }, "number-is-nan": { @@ -7451,6 +7394,12 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, "object-is": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", @@ -7545,34 +7494,20 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, - "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=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "word-wrap": "~1.2.3" } }, "os-name": { @@ -7598,6 +7533,14 @@ "dev": true, "requires": { "p-map": "^2.0.0" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } } }, "p-finally": { @@ -7631,10 +7574,13 @@ } }, "p-map": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", - "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } }, "p-reduce": { "version": "2.1.0", @@ -7643,9 +7589,9 @@ "dev": true }, "p-retry": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.1.0.tgz", - "integrity": "sha512-oepllyG9gX1qH4Sm20YAKxg1GA7L7puhvGnTfimi31P07zSIj7SDV6YtuAx9nbJF51DES+2CIIRkXs8GKqWJxA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz", + "integrity": "sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==", "dev": true, "requires": { "@types/retry": "^0.12.0", @@ -7689,9 +7635,9 @@ "dev": true }, "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { @@ -7701,9 +7647,9 @@ "dev": true }, "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", "dev": true, "requires": { "isarray": "0.0.1" @@ -7733,9 +7679,9 @@ "dev": true }, "picomatch": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", - "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.1.tgz", + "integrity": "sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA==", "dev": true }, "pify": { @@ -7868,6 +7814,20 @@ "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } } }, "read-pkg": { @@ -7914,6 +7874,14 @@ "requires": { "indent-string": "^3.0.0", "strip-indent": "^2.0.0" + }, + "dependencies": { + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + } } }, "redeyed": { @@ -7962,9 +7930,9 @@ "dev": true }, "resolve": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", - "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.13.1.tgz", + "integrity": "sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==", "dev": true, "requires": { "path-parse": "^1.0.6" @@ -7977,30 +7945,13 @@ "dev": true }, "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - } } }, "retry": { @@ -8059,23 +8010,12 @@ "is-module": "^1.0.0", "resolve": "^1.11.1", "rollup-pluginutils": "^2.8.1" - }, - "dependencies": { - "resolve": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", - "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - } } }, "rollup-pluginutils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.1.tgz", - "integrity": "sha512-J5oAoysWar6GuZo0s+3bZ6sVZAC0pfqKz68De7ZgDi5z63jOVZn1uJL/+z1jeKHNbGII8kAyHF5q8LnxSX5lQg==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", "dev": true, "requires": { "estree-walker": "^0.6.1" @@ -8103,9 +8043,9 @@ "dev": true }, "rxjs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", - "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -8157,16 +8097,16 @@ "yargs": "^14.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "execa": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-3.2.0.tgz", - "integrity": "sha512-kJJfVbI/lZE1PZYDI5VPxp8zXPO9rtxOkhpZ0jMKha56AI9y2gGVC6bkukStQf0ka5Rh15BA5m7cCCH4jmHqkw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz", + "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==", "dev": true, "requires": { "cross-spawn": "^7.0.0", @@ -8218,6 +8158,12 @@ "lru-cache": "^5.1.1" } }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -8233,12 +8179,6 @@ "p-locate": "^4.1.0" } }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, "npm-run-path": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.0.tgz", @@ -8296,12 +8236,6 @@ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, - "path-key": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", - "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==", - "dev": true - }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -8339,12 +8273,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -8356,25 +8284,10 @@ "strip-ansi": "^5.1.0" } }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, "yargs": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.0.tgz", - "integrity": "sha512-/is78VKbKs70bVZH7w4YaZea6xcJWOAwkhbR0CFuZBmYtfTYF0xjGJF43AYd8g2Uii1yJwmS5GR2vBmrc32sbg==", + "version": "14.2.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.2.tgz", + "integrity": "sha512-/4ld+4VV5RnrynMhPZJ/ZpOCGSCeghMykZ3BhdFBDa9Wy/RH6uEGNWDJog+aUlq+9OM1CFTgtYRW5Is1Po9NOA==", "dev": true, "requires": { "cliui": "^5.0.0", @@ -8439,9 +8352,9 @@ } }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true }, "semver-compare": { @@ -8463,18 +8376,18 @@ "dev": true }, "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "signal-exit": { @@ -8535,6 +8448,14 @@ "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } } }, "source-map": { @@ -8582,9 +8503,9 @@ } }, "spdx-license-ids": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", - "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "split": { @@ -8639,9 +8560,9 @@ }, "dependencies": { "stackframe": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.0.4.tgz", - "integrity": "sha512-to7oADIniaYwS3MhtCa/sQhrxidCCQiF/qp4/m5iN3ipf0Y7Xlri0f6eG29r08aL7JYl8n32AF3Q5GYBZ7K8vw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.1.0.tgz", + "integrity": "sha512-Vx6W1Yvy+AM1R/ckVwcHQHV147pTPBKWCRLrXMuPrFVfvBUc3os7PR1QLIWCMhPpRg5eX9ojzbQIMLGBwyLjqg==", "dev": true } } @@ -8690,13 +8611,45 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" } }, "string_decoder": { @@ -8720,12 +8673,20 @@ } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } } }, "strip-bom": { @@ -8753,9 +8714,9 @@ "dev": true }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, "supports-color": { @@ -8803,10 +8764,16 @@ "string-width": "^3.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "string-width": { @@ -8819,15 +8786,6 @@ "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } } } }, @@ -8857,9 +8815,9 @@ } }, "text-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.0.0.tgz", - "integrity": "sha512-F91ZqLgvi1E0PdvmxMgp+gcf6q8fMH7mhdwWfzXnl1k+GbpQDmi8l7DzLC5JTASKbwpY3TfxajAUzAXcv2NmsQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, "text-table": { @@ -8931,9 +8889,9 @@ "integrity": "sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=" }, "type": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/type/-/type-1.0.1.tgz", - "integrity": "sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", "dev": true }, "type-check": { @@ -8952,15 +8910,15 @@ "dev": true }, "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, "uglify-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.5.tgz", - "integrity": "sha512-7L3W+Npia1OCr5Blp4/Vw83tK1mu5gnoIURtT1fUVfQ3Kf8WStWV6NJz0fdoBJZls0KlweruRTLVe6XLafmy5g==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.1.tgz", + "integrity": "sha512-pnOF7jY82wdIhATVn87uUY/FHU+MDUdPLkmGFvGoclQmeu229eTkbG5gjGGBi3R7UuYYSEeYXY/TTY5j2aym2g==", "dev": true, "optional": true, "requires": { @@ -9067,9 +9025,9 @@ } }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -9088,6 +9046,39 @@ "dev": true, "requires": { "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "windows-release": { @@ -9099,10 +9090,16 @@ "execa": "^1.0.0" } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { @@ -9113,6 +9110,39 @@ "requires": { "string-width": "^2.1.1", "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "wrappy": { @@ -9166,10 +9196,10 @@ "yargs-parser": "^13.1.1" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, "find-up": { @@ -9181,6 +9211,12 @@ "locate-path": "^3.0.0" } }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -9225,15 +9261,6 @@ "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } } } }, @@ -9256,14 +9283,6 @@ "flat": "^4.1.0", "lodash": "^4.17.15", "yargs": "^13.3.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } } } } diff --git a/test/unit/utils/tv4-to-headers-message.test.js b/test/unit/utils/tv4-to-headers-message.test.js index 4b49307b..68cac17c 100644 --- a/test/unit/utils/tv4-to-headers-message.test.js +++ b/test/unit/utils/tv4-to-headers-message.test.js @@ -20,7 +20,7 @@ describe('tv4ToHeadersMessages()', () => { const message = tv4ToHeadersMessage(tv4Message, expectedHeaders); assert.equal( message, - "Header 'content-type' has value 'application/fancy-madiatype' instead of 'application/json'" + `Header 'content-type' has value 'application/fancy-madiatype' instead of 'application/json'` ); }); }); diff --git a/test/unit/validators/headers-json-example-validator.test.js b/test/unit/validators/headers-json-example-validator.test.js index c199714c..c3b0b337 100644 --- a/test/unit/validators/headers-json-example-validator.test.js +++ b/test/unit/validators/headers-json-example-validator.test.js @@ -47,7 +47,6 @@ describe('HeadersJsonExample', () => { describe('and i run validate()', () => { it("shouldn't return any errors", () => { errors = headersValidator.validate(fixtures.sampleHeaders); - console.log({ errors }); assert.equal(errors.length, 0); }); }); @@ -92,7 +91,10 @@ describe('HeadersJsonExample', () => { it('should have beautiful error message', () => { errors = headersValidator.validate(fixtures.sampleHeadersMissing); - assert.equal(errors[0].message, "Header 'header2' is missing"); + assert.equal( + errors[0].message, + `At '/header2' Missing required property: header2` + ); }); }); }); @@ -112,7 +114,7 @@ describe('HeadersJsonExample', () => { errors = headersValidator.validate(fixtures.sampleHeadersDiffers); assert.equal( errors[0].message, - "Header 'content-type' has value 'application/fancy-madiatype' instead of 'application/json'" + `At '/content-type' No enum match for: "application/fancy-madiatype"` ); }); }); From 593ea41dc86af6b935f7e45645a8bf13f728944f Mon Sep 17 00:00:00 2001 From: artem-zakharchenko Date: Wed, 4 Dec 2019 13:45:51 +0100 Subject: [PATCH 20/20] feat: infers JSON Schema Draft 7 when schema is boolean --- lib/validators/json-schema-next.js | 23 ++++++++++++++----- lib/validators/json-schema.js | 10 ++------ test/fixtures/valid-schema-v7-boolean.json | 1 + test/unit/validators/json-schema-next.test.js | 16 +++++++++++++ 4 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 test/fixtures/valid-schema-v7-boolean.json diff --git a/lib/validators/json-schema-next.js b/lib/validators/json-schema-next.js index 6f350599..908febca 100644 --- a/lib/validators/json-schema-next.js +++ b/lib/validators/json-schema-next.js @@ -26,7 +26,7 @@ const META_SCHEMA = { /** * Returns a JSON Schema Draft version of the given JSON Schema. */ -const getSchemaVersion = (jsonSchema) => { +const getExplicitSchemaVersion = (jsonSchema) => { const currentVersion = jsonSchema.$schema && jsonSchema.$schema; return Object.keys(SCHEMA_VERSIONS).find((version) => { const jsonSchemaAnnotation = SCHEMA_VERSIONS[version]; @@ -34,12 +34,18 @@ const getSchemaVersion = (jsonSchema) => { }); }; +const getImplicitSchemaVersion = (jsonSchema) => { + if (typeof jsonSchema === 'boolean') { + return 'draftV7'; + } +}; + /** * @deprecate * Attempts to resolve a schema version for a JSON Schema * without the explicit version. */ -const getImplicitSchemaVersion = (jsonSchema) => { +const getImplicitLegacySchemaVersion = (jsonSchema) => { const [schemaVersion] = [ ['draftV3', metaSchemaV3], ['draftV4', metaSchemaV4] @@ -54,12 +60,18 @@ const getImplicitSchemaVersion = (jsonSchema) => { return schemaVersion; }; +const getSchemaVersion = (jsonSchema) => { + return ( + getExplicitSchemaVersion(jsonSchema) || + getImplicitSchemaVersion(jsonSchema) || + getImplicitLegacySchemaVersion(jsonSchema) + ); +}; + class JsonSchemaValidator { constructor(jsonSchema) { this.jsonSchema = jsonSchema; - this.jsonSchemaVersion = - getSchemaVersion(this.jsonSchema) || - getImplicitSchemaVersion(this.jsonSchema); + this.jsonSchemaVersion = getSchemaVersion(jsonSchema); if (this.jsonSchemaVersion == null) { const supportedVersions = Object.keys(SCHEMA_VERSIONS).join('/'); @@ -168,6 +180,5 @@ class JsonSchemaValidator { module.exports = { JsonSchemaValidator, getSchemaVersion, - getImplicitSchemaVersion, META_SCHEMA }; diff --git a/lib/validators/json-schema.js b/lib/validators/json-schema.js index 04b26187..178f9622 100644 --- a/lib/validators/json-schema.js +++ b/lib/validators/json-schema.js @@ -1,9 +1,5 @@ const { JsonSchemaLegacy } = require('./json-schema-legacy'); -const { - JsonSchemaValidator, - getSchemaVersion, - getImplicitSchemaVersion -} = require('./json-schema-next'); +const { JsonSchemaValidator, getSchemaVersion } = require('./json-schema-next'); const errors = require('../errors'); const parseJson = require('../utils/parseJson'); @@ -32,9 +28,7 @@ function resolveJsonSchema(jsonSchema) { class JsonSchema { constructor(jsonSchema) { const resolvedJsonSchema = resolveJsonSchema(jsonSchema); - const jsonSchemaVersion = - getSchemaVersion(resolvedJsonSchema) || - getImplicitSchemaVersion(resolvedJsonSchema); + const jsonSchemaVersion = getSchemaVersion(resolvedJsonSchema); const isLegacySchema = ['draftV3', 'draftV4'].includes(jsonSchemaVersion); // Instantiate different JSON Schema validators diff --git a/test/fixtures/valid-schema-v7-boolean.json b/test/fixtures/valid-schema-v7-boolean.json new file mode 100644 index 00000000..27ba77dd --- /dev/null +++ b/test/fixtures/valid-schema-v7-boolean.json @@ -0,0 +1 @@ +true diff --git a/test/unit/validators/json-schema-next.test.js b/test/unit/validators/json-schema-next.test.js index f7219d01..5521f07e 100644 --- a/test/unit/validators/json-schema-next.test.js +++ b/test/unit/validators/json-schema-next.test.js @@ -8,6 +8,7 @@ const invalidJsonSchema6 = require('../../fixtures/invalid-schema-v6'); const validJsonSchema6 = require('../../fixtures/valid-schema-v6'); const invalidJsonSchema7 = require('../../fixtures/invalid-schema-v7'); const validJsonSchema7 = require('../../fixtures/valid-schema-v7'); +const validJsonSchema7Boolean = require('../../fixtures/valid-schema-v7-boolean'); describe('JSON Schema (next)', () => { /** @@ -206,4 +207,19 @@ describe('JSON Schema (next)', () => { }); }); }); + + /** + * Inferred JSON Schema version for boolean value schema. + */ + describe('given a JSON Schema with a boolean value', () => { + let validator; + + before(() => { + validator = new JsonSchemaValidator(validJsonSchema7Boolean); + }); + + it('should infer schema version as "draft7"', () => { + expect(validator).to.have.property('jsonSchemaVersion', 'draftV7'); + }); + }); });