diff --git a/.eslintrc b/.eslintrc index 7ebd7ac..ff0c5e8 100644 --- a/.eslintrc +++ b/.eslintrc @@ -12,6 +12,9 @@ "plugin:node/recommended", "plugin:prettier/recommended" ], + "parserOptions":{ + "ecmaVersion": 2018 + }, "rules": { "one-var": ["warn", { "var": "never", "let": "never", "const": "never" }], "no-var": 1, diff --git a/README.md b/README.md index d4abce2..42855ee 100644 --- a/README.md +++ b/README.md @@ -80,5 +80,95 @@ From there you should be able to navigate to ``` From there navigate to - - the docs, http://localhost:[YOUR PORT]/docs/ - - the api, http://localhost:[YOUR PORT]/[PATH TO API ENDPOINT] + - the docs, `http://localhost:[YOUR PORT]/docs/` + - the api, `http://localhost:[YOUR PORT]/[PATH TO API ENDPOINT]` + + +### More examples, and custom responses + +1. Get random responses from both `success` and `error` examples with the `@apiMock {RandomResponse}` annotation + ```js + /** + * @api {get} /hello/world/ + * @apiMock {RandomResponse} + * @apiSuccess {String} foo + * @apiSuccess {String} bar + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 200 OK + * { + * "foo": "hello", + * "bar": "world", + * } + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 200 OK + * { + * "lorem": "dolor", + * "ipsum": "est", + * } + * @apiError {String} bad + * @apiError {String} request + * @apiErrorExample {json} Error-Response: + * HTTP/1.1 400 OK + * { + * "bad": "hello", + * "request": "world", + * } + */ + const getExample = () => {}; + ``` + +1. Get a random `success` response with the `@apiMock {RandomSuccess}` annotation. Or get a random `error` with the `@apiMock {RandomError}` annotation + ```js + /** + * @api {get} /hello/world/ + * @apiMock {RandomSuccess} + * @apiSuccess {String} foo + * @apiSuccess {String} bar + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 200 OK + * { + * "foo": "hello", + * "bar": "world", + * } + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 200 OK + * { + * "lorem": "dolor", + * "ipsum": "est", + * } + * @apiError {String} bad + * @apiError {String} request + * @apiErrorExample {json} Error-Response: + * HTTP/1.1 400 OK + * { + * "bad": "hello", + * "request": "world", + * } + */ + const getExample = () => {}; + ``` + +1. Force a specific response status with the `@apiMock {ForceStatus} [STATUS GOES HERE]` annotation. If you use a status without a supporting example the response status is still forced, but with fallback content. + ```js + /** + * @api {get} /hello/world/ + * @apiMock {ForceStatus} 400 + * @apiSuccess {String} foo + * @apiSuccess {String} bar + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 200 OK + * { + * "foo": "hello", + * "bar": "world", + * } + * @apiError {String} bad + * @apiError {String} request + * @apiErrorExample {json} Error-Response: + * HTTP/1.1 400 OK + * { + * "bad": "hello", + * "request": "world", + * } + */ + const getExample = () => {}; + ``` diff --git a/data/example.js b/data/example.js index 9ffd32b..72b78af 100644 --- a/data/example.js +++ b/data/example.js @@ -1,5 +1,6 @@ /** * @api {get} /hello/world/ + * @apiMock {RandomResponse} * @apiSuccess {String} foo * @apiSuccess {String} bar * @apiSuccessExample {json} Success-Response: @@ -8,19 +9,40 @@ * "foo": "hello", * "bar": "world", * } + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 201 OK + * { + * "lorem": "dolor", + * "ipsum": "est", + * } + * @apiError {String} bad + * @apiError {String} request + * @apiErrorExample {json} Error-Response: + * HTTP/1.1 400 OK + * { + * "bad": "hello", + * "request": "world", + * } */ const getExample = () => {}; /** * @api {post} /hello/world/ + * @apiMock {RandomResponse} * @apiHeader {String} Authorization Authorization: Token AUTH_TOKEN * @apiSuccess {String} foo * @apiSuccess {String} bar * @apiSuccessExample {json} Success-Response: - * HTTP/1.1 200 OK + * HTTP/1.1 201 OK * { * "foo": "hello", - * "bar": "world", + * "bar": "world" + * } + * @apiError {String} detail + * @apiErrorExample {json} Error-Response: + * HTTP/1.1 401 Unauthorized + * { + * "detail": "Authentication credentials were not provided." * } */ const postExample = () => {}; @@ -34,7 +56,7 @@ const postExample = () => {}; * HTTP/1.1 200 OK * { * "foo": "hello", - * "bar": "world", + * "bar": "world" * } */ const putExample = () => {}; @@ -48,7 +70,7 @@ const putExample = () => {}; * HTTP/1.1 200 OK * { * "foo": "hello", - * "bar": "world", + * "bar": "world" * } */ const patchExample = () => {}; @@ -62,7 +84,7 @@ const patchExample = () => {}; * HTTP/1.1 200 OK * { * "foo": "hello", - * "bar": "world", + * "bar": "world" * } */ const deleteExample = () => {}; diff --git a/package.json b/package.json index 150b005..ae82246 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "apidoc-mock", - "version": "0.0.1", + "version": "1.0.0", "description": "Creates a mock server from apiDoc comments.", "author": "cdcabrera", "private": true, @@ -21,9 +21,10 @@ "docker:build": "docker build -t apidoc-mock-test .", "serve": "node src/index.js", "test": "eslint ./src/", - "build": "apidoc -i ./data -o ./docs", + "build": "apidoc --parse-parsers apimock=./src/api_mock.js -i ./data -o ./docs", "build:serve": "npm run build && npm run serve", - "start": "nodemon --watch data npm run build:serve" + "start": "nodemon --watch data npm run build:serve", + "opts": "apidoc --help" }, "apidoc": { "title": "Custom apiDocs", @@ -33,18 +34,18 @@ "dependencies": { "apidoc": "^0.17.6", "express": "^4.16.3", - "nodemon": "^1.17.4" + "nodemon": "^1.18.1" }, "devDependencies": { "babel-eslint": "^8.2.3", - "eslint": "^4.19.1", - "eslint-config-esnext": "^2.0.0", - "eslint-config-node": "^2.0.0", + "eslint": "^5.1.0", + "eslint-config-esnext": "^3.0.0", + "eslint-config-node": "^3.0.0", "eslint-config-prettier": "^2.9.0", "eslint-plugin-babel": "^5.1.0", - "eslint-plugin-import": "^2.11.0", + "eslint-plugin-import": "^2.13.0", "eslint-plugin-node": "^6.0.1", - "eslint-plugin-prettier": "^2.6.0", - "prettier": "^1.12.1" + "eslint-plugin-prettier": "^2.6.2", + "prettier": "^1.13.7" } } diff --git a/src/api_mock.js b/src/api_mock.js new file mode 100644 index 0000000..d5f8b34 --- /dev/null +++ b/src/api_mock.js @@ -0,0 +1,27 @@ +let group = ''; + +const parse = (content, source, defaultGroup) => { + group = defaultGroup || 'settings'; + + const keyValue = content.split('}'); + + let key = (keyValue[0] || '').replace(/({|^\s+|\s+$)/, ''); + const value = (keyValue[1] || '').replace(/(^\s+|\s+$)/, ''); + + key = key.replace(/(?:^\w|[A-Z]|\b\w)/g, function(letter, index) { + return index === 0 ? letter.toLowerCase() : letter.toUpperCase(); + }); + + return { [key]: value }; +}; + +const getGroup = () => group; + +const path = () => `local.mock.${getGroup()}`; + +module.exports = { + parse, + path, + getGroup: getGroup, + method: 'push' +}; diff --git a/src/index.js b/src/index.js index 87c7c12..19ef7fd 100644 --- a/src/index.js +++ b/src/index.js @@ -2,113 +2,403 @@ const path = require('path'); const fs = require('fs'); const apidoc = require('apidoc'); const express = require('express'); + +const apiDocsConfig = { + src: path.join(__dirname, '../data'), + dest: path.join(__dirname, '../docs'), + parsers: { + apimock: path.join(__dirname, 'api_mock.js') + } +}; const apiJsonFile = path.join(__dirname, '../docs/api_data.json'); const port = process.env.PORT || 8000; +const apiDocRoute = 'docs'; -const buildApiDocs = config => { - let result; +/** + * Class LoadApi + */ +class LoadApi { + /** + * Create a mock API server from ApiDoc. + * + * @param apiDocsConfig {Object} + * @param apiJsonFile {String} + * @param port {Number} + * @param apiDocRoute {String} + */ + constructor({ apiDocsConfig, apiJsonFile, port, apiDocRoute }) { + const apiJson = LoadApi.buildApiDocs(apiDocsConfig, apiJsonFile); - try { - result = apidoc.createDoc(config); - } catch (e) { - console.error(`apidoc error...${e.message}`); + if (apiJson) { + this.app = express(); + this.setupResponse(apiDocRoute); + this.setupApi(apiJson, port); + } } - if (result === false) { - console.error('apidoc error... exiting.'); - return; - } + /** + * Set http status + * + * @param examples {Array} + * @param response {String} + * @param type {String} + * @param url {String} + * @returns {Object} + */ + static parseStatus(examples = [], response = null, type = null, url = null) { + return examples.map(val => { + const status = parseInt(val.content.split(/\s/)[1], 10) || 200; + const route = type && url ? `, mismatch for "${type}" route ${url}` : ''; - console.info('apidoc finished... loading JSON'); - return JSON.parse(fs.readFileSync(apiJsonFile, 'utf8')); -}; + // ToDo: ApiDoc currently has no "information" or "redirect" distinction, consider plugin + if (response === 'success' && status >= 400) { + console.warn(`Success example given with status of ${status}${route}`); + } -const loadApi = () => { - const app = express(); + if (response === 'error' && status < 400) { + console.warn(`Error example given with status of ${status}${route}`); + } - let routesLoaded = 0; + return { + status, + ...val + }; + }); + } - app.use('/docs', express.static('docs')); + /** + * Parse custom mock settings. + * + * @param mockSettings {Array} + * @returns {Object} + */ + static parseMockSettings(mockSettings = {}) { + const settings = {}; - app.use((request, response, next) => { - const hasOrigin = request.headers.origin != null; + if (mockSettings.mock && mockSettings.mock.settings && mockSettings.mock.settings.length) { + mockSettings.mock.settings.forEach(val => { + const keys = Object.keys(val || {}); + const key = keys[0] || null; - response.set('Access-Control-Allow-Origin', hasOrigin ? request.headers.origin : '*'); - response.set('Access-Control-Allow-Credentials', !hasOrigin); - response.set('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, HEAD, OPTIONS, PATCH'); + switch (key) { + case 'forceStatus': + settings.forceStatus = parseInt(val[key], 10); + break; + case 'response': + settings.response = 'response'; + break; + case 'randomResponse': + settings.response = 'response'; + settings.reload = true; + break; + case 'randomSuccess': + settings.response = 'success'; + settings.reload = true; + break; + case 'randomError': + settings.response = 'error'; + settings.reload = true; + break; + } + }); + } - const requestHeaders = request.headers['access-control-request-headers']; + return settings; + } - if (requestHeaders != null) { - response.set('Access-Control-Allow-Headers', requestHeaders); + /** + * Return passed mock mime type and parsed content + * + * @param content {String} + * @param type {String} + * @returns {{parsedContent: string, parsedType: string}} + */ + static parseContentAndType(content = '', type = 'text') { + const parsable = /^HTTP/.test(content); + let parsedContent = content; + let parsedType; + + if (parsable) { + parsedContent = content + .split(/\n/) + .slice(1) + .join('\n'); } - if (request.method === 'OPTIONS') { - response.end(); - } else { - next(); + switch (type) { + case 'json': + parsedType = 'application/json'; + + if (parsable) { + parsedContent = `{ ${content + .split('{') + .slice(1) + .join('{')}`; + } + break; + case 'xml': + case 'html': + parsedType = `text/${type}`; + break; + case 'svg': + parsedType = 'image/svg+xml'; + break; + case 'csv': + parsedType = 'text/csv'; + break; + default: + parsedType = 'text/plain'; + break; } - }); - apiJson.forEach(value => { + return { content: parsedContent, type: parsedType }; + } + + /** + * Compile/build ApiDoc documentation. + * + * @param apiDocsConfig {Object} + * @param apiJsonFile {String} + * @returns {Object} + */ + static buildApiDocs(apiDocsConfig = {}, apiJsonFile = null) { + let result; + try { - if (value.success.examples && value.success.examples.length) { - const example = - value.success.examples[Math.floor(Math.random() * value.success.examples.length)]; - - if (example.type === 'json') { - app[value.type](value.url, (req, res) => { - const content = `{ ${example.content - .split('{') - .slice(1) - .join('{')}`; - - res.set('Cache-Control', 'no-cache'); - - if (value.header && value.header.fields.Header && value.header.fields.Header.length) { - for (let i = 0; i < value.header.fields.Header.length; i++) { - const headerValue = value.header.fields.Header[i]; - - if ( - !headerValue.optional && - headerValue.field && - /authorization/i.test(headerValue.field) - ) { - const authorization = req.get('authorization'); - - if (!authorization) { - res.append('WWW-Authenticate', 'Spoof response'); - res.status(401); - res.end('Authorization Required'); - return; - } - } - } - } + result = apidoc.createDoc(apiDocsConfig); + } catch (e) { + console.error(`ApiDoc error...${e.message}`); + } + + if (result === false) { + console.error('ApiDoc error... exiting.'); + return; + } + + console.info('ApiDoc finished... loading JSON'); + return JSON.parse(fs.readFileSync(apiJsonFile, 'utf8')); + } + + /** + * Return forced response, or a general example. + * + * @param mockSettings {Object} + * @param exampleObjects {Array} + * @param successObjects {Array} + * @param errorObjects {Array} + * @returns {{type: string, status: number, content: string}} + */ + static exampleResponse(mockSettings, exampleObjects, successObjects, errorObjects) { + let example; + let tempObjects; - res.set('Content-Type', 'application/json'); - res.send(content); - }); + switch (mockSettings.response) { + case 'response': + tempObjects = exampleObjects; + break; + case 'error': + tempObjects = errorObjects; + break; + case 'success': + default: + tempObjects = successObjects; + break; + } - routesLoaded += 1; - console.info(`Loading "${value.type}" route ${value.url}...`); + if (/\d/.test(mockSettings.forceStatus)) { + example = exampleObjects.filter(val => { + if (val.status === mockSettings.forceStatus) { + return true; } + }); + + if (example.length) { + example = example[Math.floor(Math.random() * example.length)]; + } else { + example = { + type: 'text', + status: mockSettings.forceStatus, + content: `Missing example for ${mockSettings.forceStatus} status` + }; } - } catch (e) { - console.warn(e.message); + } else if (tempObjects) { + example = tempObjects[Math.floor(Math.random() * tempObjects.length)]; } - }); - if (routesLoaded) { - app.listen(port, () => console.info(`Mock server listening on port ${port}`)); + if (!example) { + switch (mockSettings.response) { + case 'error': + example = { + type: 'text', + status: 404, + content: 'Error' + }; + break; + case 'response': + case 'success': + default: + example = { + type: 'text', + status: 200, + content: 'Success' + }; + break; + } + } + + return example; } -}; -const apiJson = buildApiDocs({ - src: path.join(__dirname, '../data'), - dest: path.join(__dirname, '../docs') -}); + /** + * Return a 401 specific example. + * + * @param errorObjects {Array} + * @returns {{type: string, status: number, content: string}} + */ + static parseAuthExample(errorObjects = []) { + const authExample = errorObjects.filter(val => { + if (val.status === 401) { + return true; + } + }); + + return (authExample && authExample[Math.floor(Math.random() * authExample.length)]) || {}; + } + + /** + * Open request headers up. Parse OPTIONS or continue + * + * @param apiDocRoute {String} + */ + setupResponse(apiDocRoute) { + this.app.use(`/${apiDocRoute}`, express.static(apiDocRoute)); + + this.app.use((request, response, next) => { + const hasOrigin = request.headers.origin != null; + + response.set('Access-Control-Allow-Origin', hasOrigin ? request.headers.origin : '*'); + response.set('Access-Control-Allow-Credentials', !hasOrigin); + response.set('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, HEAD, OPTIONS, PATCH'); + + const requestHeaders = request.headers['access-control-request-headers']; + + if (requestHeaders != null) { + response.set('Access-Control-Allow-Headers', requestHeaders); + } + + if (request.method === 'OPTIONS') { + response.end(); + } else { + next(); + } + }); + } + + /** + * Setup API response. + * + * @param apiJson {Array} + * @param port {Number} + */ + setupApi(apiJson = [], port = 8000) { + let routesLoaded = 0; + + apiJson.forEach(value => { + try { + const successExamples = (value.success && value.success.examples) || []; + const errorExamples = (value.error && value.error.examples) || []; + const hasNoExamples = !successExamples.length && !errorExamples.length; + const mockSettings = LoadApi.parseMockSettings(value); + const successObjects = LoadApi.parseStatus( + successExamples, + 'success', + value.type, + value.url + ); + const errorObjects = LoadApi.parseStatus(errorExamples, 'error', value.type, value.url); + const authExample = LoadApi.parseAuthExample(errorObjects); + const exampleObjects = successObjects.concat(errorObjects); + + let example; + + if (!mockSettings.reload) { + example = LoadApi.exampleResponse( + mockSettings, + exampleObjects, + successObjects, + errorObjects + ); + } -if (apiJson) { - loadApi(); + this.app[value.type](value.url, (request, response) => { + if (mockSettings.reload) { + example = LoadApi.exampleResponse( + mockSettings, + exampleObjects, + successObjects, + errorObjects + ); + } + + const httpStatus = example.status; + const { content, type } = LoadApi.parseContentAndType(example.content, example.type); + + response.set('Cache-Control', 'no-cache'); + + if (value.header && value.header.fields.Header && value.header.fields.Header.length) { + for (let i = 0; i < value.header.fields.Header.length; i++) { + const headerValue = value.header.fields.Header[i]; + + if ( + !headerValue.optional && + headerValue.field && + /authorization/i.test(headerValue.field) + ) { + const authorization = request.get('authorization'); + + if (!authorization) { + const authObj = LoadApi.parseContentAndType( + authExample.content, + authExample.type + ); + + response.append('WWW-Authenticate', 'Spoof response'); + response.status(401); + response.set('Content-Type', authObj.type); + response.end(authObj.content || 'Authorization Required'); + return; + } + } + } + } + + response.set('Content-Type', type); + response.status(httpStatus); + response.send(content); + }); + + routesLoaded += 1; + console.info( + `Loading "${value.type}" route ${value.url}... ${ + hasNoExamples ? 'No examples found, using fallback response' : '' + }` + ); + } catch (e) { + console.warn(e.message); + } + }); + + if (routesLoaded) { + this.app.listen(port, () => console.info(`Mock server listening on port ${port}`)); + } else { + console.info(`Mock server waiting...`); + } + } } + +new LoadApi({ + apiDocsConfig, + apiJsonFile, + port, + apiDocRoute +}); diff --git a/yarn.lock b/yarn.lock index d8675d5..f3b9486 100644 --- a/yarn.lock +++ b/yarn.lock @@ -95,10 +95,20 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" +acorn-jsx@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e" + dependencies: + acorn "^5.0.3" + acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" +acorn@^5.0.3, acorn@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" + acorn@^5.5.0: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" @@ -107,6 +117,10 @@ ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" +ajv-keywords@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" + ajv@^5.2.3, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" @@ -116,6 +130,15 @@ ajv@^5.2.3, ajv@^5.3.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" +ajv@^6.0.1, ajv@^6.5.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.2.tgz#678495f9b82f7cca6be248dd92f59bff5e1f4360" + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.1" + ansi-align@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" @@ -244,7 +267,7 @@ atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" -babel-code-frame@^6.22.0: +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -252,7 +275,7 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-eslint@^8.0.2, babel-eslint@^8.2.3: +babel-eslint@^8.2.3: version "8.2.3" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf" dependencies: @@ -566,6 +589,16 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -598,6 +631,13 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -694,6 +734,24 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.10.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -702,21 +760,21 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -eslint-config-esnext@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-esnext/-/eslint-config-esnext-2.0.0.tgz#3d6c9e87ed0a0ee72f2797138eb0bceb20897ca2" +eslint-config-esnext@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-esnext/-/eslint-config-esnext-3.0.0.tgz#2f8c41801055906e345a9dab9c57afd604a60c78" dependencies: - babel-eslint "^8.0.2" - eslint "^4.0.0" - eslint-plugin-babel "^4.1.2" - eslint-plugin-import "^2.8.0" + babel-eslint "^8.2.3" + eslint "^4.19.1" + eslint-plugin-babel "^5.1.0" + eslint-plugin-import "^2.12.0" -eslint-config-node@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-node/-/eslint-config-node-2.0.0.tgz#db4fa58bf8785e21e1a32b93dc1622ba39b377c0" +eslint-config-node@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-node/-/eslint-config-node-3.0.0.tgz#a58d16797b4bb8a0d0d98f0998b2aabc046090a6" dependencies: - eslint "^4.0.0" - eslint-config-esnext "^2.0.0" + eslint "^4.19.1" + eslint-config-esnext "^3.0.0" eslint-config-prettier@^2.9.0: version "2.9.0" @@ -738,19 +796,15 @@ eslint-module-utils@^2.2.0: debug "^2.6.8" pkg-dir "^1.0.0" -eslint-plugin-babel@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz#79202a0e35757dd92780919b2336f1fa2fe53c1e" - eslint-plugin-babel@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-5.1.0.tgz#9c76e476162041e50b6ba69aa4eae3bdd6a4e1c3" dependencies: eslint-rule-composer "^0.3.0" -eslint-plugin-import@^2.11.0, eslint-plugin-import@^2.8.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz#15aeea37a67499d848e8e981806d4627b5503816" +eslint-plugin-import@^2.12.0, eslint-plugin-import@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz#df24f241175e312d91662dc91ca84064caec14ed" dependencies: contains-path "^0.1.0" debug "^2.6.8" @@ -772,9 +826,9 @@ eslint-plugin-node@^6.0.1: resolve "^1.3.3" semver "^5.4.1" -eslint-plugin-prettier@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" +eslint-plugin-prettier@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.2.tgz#71998c60aedfa2141f7bfcbf9d1c459bf98b4fad" dependencies: fast-diff "^1.1.1" jest-docblock "^21.0.0" @@ -790,11 +844,22 @@ eslint-scope@^3.7.1, eslint-scope@~3.7.1: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" + eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^4.0.0, eslint@^4.19.1: +eslint@^4.19.1: version "4.19.1" resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" dependencies: @@ -837,6 +902,50 @@ eslint@^4.0.0, eslint@^4.19.1: table "4.0.2" text-table "~0.2.0" +eslint@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.1.0.tgz#2ed611f1ce163c0fb99e1e0cda5af8f662dff645" + dependencies: + ajv "^6.5.0" + babel-code-frame "^6.26.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^4.0.0" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^4.0.0" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^5.2.0" + is-resolvable "^1.1.0" + js-yaml "^3.11.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.5" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.1.0" + require-uncached "^1.0.3" + semver "^5.5.0" + string.prototype.matchall "^2.0.0" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^4.0.3" + text-table "^0.2.0" + espree@^3.5.4: version "3.5.4" resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" @@ -844,11 +953,18 @@ espree@^3.5.4: acorn "^5.5.0" acorn-jsx "^3.0.0" +espree@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634" + dependencies: + acorn "^5.6.0" + acorn-jsx "^4.1.1" + esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" -esquery@^1.0.0: +esquery@^1.0.0, esquery@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" dependencies: @@ -956,7 +1072,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -external-editor@^2.0.4: +external-editor@^2.0.4, external-editor@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: @@ -985,6 +1101,10 @@ fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + fast-diff@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" @@ -1057,6 +1177,10 @@ for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -1100,7 +1224,7 @@ fsevents@^1.1.2: nan "^2.9.2" node-pre-gyp "^0.9.0" -function-bind@^1.0.2: +function-bind@^1.0.2, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -1161,6 +1285,10 @@ globals@^11.0.1, globals@^11.1.0: version "11.5.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" +globals@^11.7.0: + version "11.7.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" + globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" @@ -1206,6 +1334,10 @@ has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -1331,6 +1463,24 @@ inquirer@^3.0.6: strip-ansi "^4.0.0" through "^2.3.6" +inquirer@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.1.0" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^5.5.2" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + invariant@^2.2.0: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -1373,6 +1523,10 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + is-ci@^1.0.10: version "1.1.0" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" @@ -1391,6 +1545,10 @@ is-data-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + is-descriptor@^0.1.0: version "0.1.6" resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" @@ -1504,7 +1662,13 @@ is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" -is-resolvable@^1.0.0: +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + dependencies: + has "^1.0.1" + +is-resolvable@^1.0.0, is-resolvable@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" @@ -1516,6 +1680,10 @@ is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -1550,6 +1718,13 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +js-yaml@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@^3.9.1: version "3.11.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef" @@ -1565,6 +1740,10 @@ json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -1636,7 +1815,7 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4: +lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -1824,6 +2003,10 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" +nice-try@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" + node-pre-gyp@^0.9.0: version "0.9.1" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.9.1.tgz#f11c07516dd92f87199dbc7e1838eab7cd56c9e0" @@ -1839,9 +2022,9 @@ node-pre-gyp@^0.9.0: semver "^5.3.0" tar "^4" -nodemon@^1.17.4: - version "1.17.4" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.17.4.tgz#243ff9c69ffbf1175f2460f9b023f35a072c15e9" +nodemon@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.1.tgz#873d2f7799662c549f7ea557db6934d5cbf665d6" dependencies: chokidar "^2.0.2" debug "^3.1.0" @@ -1931,6 +2114,10 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" +object-keys@^1.0.8: + version "1.0.12" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2" + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -2052,7 +2239,7 @@ path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" -path-key@^2.0.0: +path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" @@ -2116,9 +2303,9 @@ prepend-http@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" -prettier@^1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" +prettier@^1.13.7: + version "1.13.7" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" process-nextick-args@~2.0.0: version "2.0.0" @@ -2151,6 +2338,10 @@ pstree.remy@^1.1.0: dependencies: ps-tree "^1.1.0" +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + qs@6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" @@ -2220,7 +2411,13 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regexpp@^1.0.1: +regexp.prototype.flags@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" + dependencies: + define-properties "^1.1.2" + +regexpp@^1.0.1, regexpp@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" @@ -2303,6 +2500,12 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" +rxjs@^5.5.2: + version "5.5.11" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.11.tgz#f733027ca43e3bec6b994473be4ab98ad43ced87" + dependencies: + symbol-observable "1.0.1" + safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -2543,6 +2746,16 @@ string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string.prototype.matchall@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-2.0.0.tgz#2af8fe3d2d6dc53ca2a59bd376b089c3c152b3c8" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.10.0" + function-bind "^1.1.1" + has-symbols "^1.0.0" + regexp.prototype.flags "^1.2.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -2573,7 +2786,7 @@ strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" -strip-json-comments@~2.0.1: +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -2587,6 +2800,10 @@ supports-color@^5.2.0, supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + table@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" @@ -2598,6 +2815,17 @@ table@4.0.2: slice-ansi "1.0.0" string-width "^2.1.1" +table@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" + dependencies: + ajv "^6.0.1" + ajv-keywords "^3.0.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" + tar@^4: version "4.4.2" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.2.tgz#60685211ba46b38847b1ae7ee1a24d744a2cd462" @@ -2616,7 +2844,7 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -text-table@~0.2.0: +text-table@^0.2.0, text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2754,6 +2982,12 @@ update-notifier@^2.3.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" +uri-js@^4.2.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + dependencies: + punycode "^2.1.0" + urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"