From 8bcb4a35fc2e22af31b8d51fc5c3cb4e9170c08f Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 12 Nov 2017 13:22:25 -0800 Subject: [PATCH] Refactor SplatNet data updaters This also changes the output paths for SplatNet images to make them follow the original paths (rather than just using the original filenames). --- package.json | 1 + src/js/components/splatoon/Stage.vue | 2 +- src/js/filters.js | 12 +- src/updater/update.js | 262 +++++------------- .../updaters/OriginalGearImageUpdater.js | 23 ++ src/updater/updaters/Updater.js | 138 +++++++++ yarn.lock | 162 ++++++++++- 7 files changed, 386 insertions(+), 214 deletions(-) create mode 100644 src/updater/updaters/OriginalGearImageUpdater.js create mode 100644 src/updater/updaters/Updater.js diff --git a/package.json b/package.json index 1ca9b26..86ddd08 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "html-loader": "^0.5.0", "html-webpack-plugin": "^2.30.1", "json-stable-stringify": "^1.0.1", + "jsonpath": "^1.0.0", "make-runnable": "^1.3.6", "mkdirp": "^0.5.1", "moment-timezone": "^0.5.13", diff --git a/src/js/components/splatoon/Stage.vue b/src/js/components/splatoon/Stage.vue index 5341811..9912764 100644 --- a/src/js/components/splatoon/Stage.vue +++ b/src/js/components/splatoon/Stage.vue @@ -54,7 +54,7 @@ export default { }, largeImage() { if (this.stageDetails) - return Vue.filter('localSplatNetImageUrl')(this.stageDetails.largeImage || this.stageDetails.image); + return this.stageDetails.largeImage || Vue.filter('localSplatNetImageUrl')(this.stageDetails.image); }, style() { return { diff --git a/src/js/filters.js b/src/js/filters.js index ee83221..e6555c2 100644 --- a/src/js/filters.js +++ b/src/js/filters.js @@ -2,15 +2,9 @@ import Vue from 'vue'; // Local hosting of SplatNet images Vue.filter('localSplatNetImageUrl', function(value) { - if (value) { - // Quick hack to detect whether this is a bundled image or a SplatNet image - if (value.indexOf('assets/img/') === 0) - return value; - - // This is a SplatNet image, so let's adjust the URL - let filename = value.replace(/^.*[\\\/]/, ''); - return `assets/img/splatnet/${filename}`; - } + // Have to use a relative path here for the screenshot generator. + // May need to change this in the future. + return 'assets/splatnet' + value; }); // Short date format (e.g., 8/15 or 15/8) diff --git a/src/updater/update.js b/src/updater/update.js index ccf97db..750f70f 100644 --- a/src/updater/update.js +++ b/src/updater/update.js @@ -1,218 +1,92 @@ require('./bootstrap'); -const path = require('path'); -const fs = require('fs'); -const mkdirp = require('mkdirp'); const splatnet = require('./splatnet'); -const raven = require('raven'); -const dataPath = path.resolve('public/data'); -const splatnetImagePath = path.resolve('public/assets/img/splatnet'); +const Updater = require('./updaters/Updater'); +const OriginalGearImageUpdater = require('./updaters/OriginalGearImageUpdater'); -/** - * Updaters - */ +const updaters = [ + // Original gear images + new OriginalGearImageUpdater(), -async function updateSchedules() { - let data = await handleRequest({ - title: 'map schedules', - filename: `${dataPath}/schedules.json`, - request: splatnet.getSchedules(), - }); + // Schedules + new Updater({ + name: 'Schedules', + filename: 'schedules.json', + request: () => splatnet.getSchedules(), + imagePaths: [ + '$..stage_a.image', + '$..stage_b.image', + ], + }), - // Download stage images - if (data) { - for (let type of ['regular', 'gachi', 'league']) { - if (data[type]) { - for (let schedule of data[type]) { - await maybeDownloadImage(schedule.stage_a.image); - await maybeDownloadImage(schedule.stage_b.image); - } - } - } - } -} + // Co-op Schedules + new Updater({ + name: 'Co-op Schedules', + filename: 'coop-schedules.json', + request: () => splatnet.getCoopSchedules(), + imagePaths: [ + '$..stage.image', + '$..weapons[*].image', + ], + }), -async function updateCoopSchedules() { - let data = await handleRequest({ - title: 'co-op schedules', - filename: `${dataPath}/coop-schedules.json`, - request: splatnet.getCoopSchedules(), - }); + // Timeline + new Updater({ + name: 'Timeline', + filename: 'timeline.json', + request: () => splatnet.getTimeline(), + rootKeys: ['coop', 'weapon_availability'], + imagePaths: [ + '$.coop..gear.image', + '$.coop..gear.brand.image', + '$.weapon_availability..weapon.image', + '$.weapon_availability..weapon.special.image_a', + '$.weapon_availability..weapon.sub.image_a', + ], + }), - // Download images - if (data) { - for (let schedule of data.details) { - await maybeDownloadImage(schedule.stage.image); - - for (let weapon of schedule.weapons) { - // Mystery weapons are null, so we have to make sure we don't attempt to download their images - if (weapon) - await maybeDownloadImage(weapon.image); - } - } - } -} - -async function updateTimeline() { - let data = await handleRequest({ - title: 'timeline', - filename: `${dataPath}/timeline.json`, - request: splatnet.getTimeline(), - transformer: responseData => { - // Filter out everything but the data we need - let data = { coop: null, weapon_availability: null }; - if (responseData.coop && responseData.coop.importance > -1) - data.coop = responseData.coop; - if (responseData.weapon_availability && responseData.weapon_availability.importance > -1) - data.weapon_availability = responseData.weapon_availability; - return data; - }, - }); - - // Download images - if (data) { - if (data.coop && data.coop.reward_gear) { - await maybeDownloadImage(data.coop.reward_gear.gear.image); - await maybeDownloadImage(data.coop.reward_gear.gear.brand.image); - } - - if (data.weapon_availability && data.weapon_availability.availabilities) { - for (let availability of data.weapon_availability.availabilities) { - let weapon = availability.weapon; - await maybeDownloadImage(weapon.image); - await maybeDownloadImage(weapon.special.image_a); - await maybeDownloadImage(weapon.sub.image_a); - } - } - } -} - -async function updateFestivals() { - let data = await handleRequest({ - title: 'festivals', - filename: `${dataPath}/festivals.json`, - request: async function() { + // Festivals + new Updater({ + name: 'Festivals', + filename: 'festivals.json', + async request() { return { na: await splatnet.getCombinedFestivals('NA'), eu: await splatnet.getCombinedFestivals('EU'), jp: await splatnet.getCombinedFestivals('JP'), }; - }(), - }); - - // Download banner/stage images - if (data) { - for (let region of ['na', 'eu', 'jp']) { - for (let festival of data[region].festivals) { - await maybeDownloadImage(festival.images.alpha); - await maybeDownloadImage(festival.images.bravo); - await maybeDownloadImage(festival.images.panel); - await maybeDownloadImage(festival.special_stage.image); - } - } - } -} - -async function updateMerchandises() { - let data = await handleRequest({ - title: 'merchandises', - filename: `${dataPath}/merchandises.json`, - request: splatnet.getMerchandises(), - transformer: responseData => { - // Filter out everything but the data we need - let data = { merchandises: null }; - if (responseData.merchandises) - data.merchandises = responseData.merchandises; - return data; }, - }); + imagePaths: [ + '$..images.alpha', + '$..images.bravo', + '$..images.panel', + '$..special_stage.image', + ], + }), - // Download merchandise/skill images - if (data && data.merchandises) { - for (let merchandise of data.merchandises) { - await maybeDownloadImage(merchandise.gear.image); - await maybeDownloadImage(merchandise.gear.brand.image); - await maybeDownloadImage(merchandise.gear.brand.frequent_skill.image); - await maybeDownloadImage(merchandise.skill.image); - } - } -} + // Merchandises + new Updater({ + name: 'Merchandises', + filename: 'merchandises.json', + request: () => splatnet.getMerchandises(), + rootKeys: ['merchandises'], + imagePaths: [ + '$..gear.image', + '$..gear.brand.image', + '$..gear.brand.frequent_skill.image', + '$..skill.image', + ], + }), +]; async function updateAll() { - await updateSchedules(); - await updateCoopSchedules(); - await updateTimeline(); - await updateFestivals(); - await updateMerchandises(); - return 'Done.'; -} + for (let updater of updaters) + await updater.update(); -/** - * Utility functions - */ - -function writeFile(filename, data) { - mkdirp(path.dirname(filename)); - fs.writeFileSync(filename, data); -} - -async function handleRequest(options) { - options = Object.assign({ isJson: true }, options); - - console.info(`Updating ${options.title}...`); - - try { - // Get the response data - let data = await options.request; - - // If we have a data transformer, use it - if (options.transformer) - data = options.transformer(data); - - let fileData = (options.isJson) ? JSON.stringify(data) : data; - - // Write the data - writeFile(options.filename, fileData); - console.info(`Updated ${options.title}.`); - - return data; - } catch (e) { - raven.captureException(e); - console.error(`Couldn\'t update ${options.title}.`); - console.error(e); - } -} - -function maybeDownloadImage(imagePath) { - if (!imagePath) - return; - - // Quick hack to detect whether this is our own hosted image - if (imagePath.indexOf('assets/img/') === 0) - return; - - let filename = path.basename(imagePath); - let localPath = `${splatnetImagePath}/${filename}`; - - // If we've already downloaded the image, we don't need to do anything - if (fs.existsSync(localPath)) - return; - - // Otherwise, download the image - return handleRequest({ - title: `image ${filename}`, - filename: localPath, - request: splatnet.getImage(imagePath), - isJson: false, - }); + return 'Done'; } module.exports = { - updateSchedules, - updateCoopSchedules, - updateTimeline, - updateFestivals, - updateMerchandises, updateAll, } diff --git a/src/updater/updaters/OriginalGearImageUpdater.js b/src/updater/updaters/OriginalGearImageUpdater.js new file mode 100644 index 0000000..ba33f7a --- /dev/null +++ b/src/updater/updaters/OriginalGearImageUpdater.js @@ -0,0 +1,23 @@ +const Updater = require('./Updater'); +const path = require('path'); +const fs = require('fs'); +const dataPath = path.resolve('src/js/data'); + +class OriginalGearImageUpdater extends Updater { + constructor() { + super({ + name: 'Original Gear', + imagePaths: ['$..image'], + }); + } + + async update() { + // Get the list of skills + let data = JSON.parse(fs.readFileSync(`${dataPath}/skills.json`)); + + // Retrieve skill images + await this.downloadImages(data); + } +} + +module.exports = OriginalGearImageUpdater; diff --git a/src/updater/updaters/Updater.js b/src/updater/updaters/Updater.js new file mode 100644 index 0000000..312e5be --- /dev/null +++ b/src/updater/updaters/Updater.js @@ -0,0 +1,138 @@ +const path = require('path'); +const fs = require('fs'); +const mkdirp = require('mkdirp'); +const jsonpath = require('jsonpath'); +const splatnet = require('../splatnet'); +const raven = require('raven'); + +const dataPath = path.resolve('public/data'); +const splatnetAssetPath = path.resolve('public/assets/splatnet'); + +class Updater { + constructor(options = {}) { + this.options = options; + } + + async update() { + this.info('Updating data...'); + + // Retrieve the data + let data = await this.handleRequest(this.getData()); + + // Filter the root keys if necessary + data = this.filterRootKeys(data); + + // Convert the data to a JSON string + let dataString = JSON.stringify(data); + + // Write the data to disk + let localPath = `${dataPath}/${this.options.filename}`; + this.writeFile(localPath, dataString); + + // Download images if necessary + await this.downloadImages(data); + + this.info('Done.'); + } + + getData() { + return this.options.request(); + } + + async handleRequest(request) { + try { + return await request; + } + catch (e) { + // Send the error to Sentry + raven.captureException(e); + + // Log the message to the console + this.error(`Couldn't handle request: ${e.toString()}`); + + // Re-throw + throw e; + } + } + + filterRootKeys(data) { + if (this.options.rootKeys) { + let result = {}; + + for (let key of this.options.rootKeys) { + let value = data[key]; + result[key] = (this.shouldIncludeRootValue(value)) ? value : null; + } + + return result; + } + + return data; + } + + shouldIncludeRootValue(value) { + if (!value) + return false; + + // Remove timeline items with an importance of -1 + if (value.hasOwnProperty('importance')) + return value.importance > -1; + + return true; + } + + writeFile(filename, data) { + mkdirp(path.dirname(filename)); + fs.writeFileSync(filename, data); + } + + async downloadImages(data) { + if (this.options.imagePaths) { + for (let expression of this.options.imagePaths) { + let splatnetImages = jsonpath.query(data, expression); + for (let splatnetImage of splatnetImages) + await this.maybeDownloadImage(splatnetImage); + } + } + } + + async maybeDownloadImage(imagePath) { + if (!imagePath) + return; + + let localPath = splatnetAssetPath + imagePath; + + // Check whether the image has already been downloaded + if (fs.existsSync(localPath)) + return; + + // Otherwise, download the image + try { + this.info(`Downloading image: ${imagePath}`); + let image = await this.handleRequest(splatnet.getImage(imagePath)); + this.writeFile(localPath, image); + } catch (e) { } + } + + /** + * Log helpers + */ + + formatLogMessage(message) { + return `[Updater] [${this.options.name}] ${message}`; + } + + log(message) { + console.log(this.formatLogMessage(message)); + } + + info(message) { + console.info(this.formatLogMessage(message)); + } + + error(message) { + console.error(this.formatLogMessage(message)); + } +} + +module.exports = Updater; diff --git a/yarn.lock b/yarn.lock index 4103e50..31788b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +JSONSelect@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/JSONSelect/-/JSONSelect-0.4.0.tgz#a08edcc67eb3fcbe99ed630855344a0cf282bb8d" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1130,6 +1134,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +cjson@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/cjson/-/cjson-0.2.1.tgz#73cd8aad65d9e1505f9af1744d3b79c1527682a5" + clap@^1.0.9: version "1.2.3" resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51" @@ -1223,6 +1231,10 @@ colormin@^1.0.5: css-color-names "0.0.4" has "^1.0.1" +colors@0.5.x: + version "0.5.1" + resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774" + colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -1597,6 +1609,10 @@ deep-extend@~0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" +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" @@ -1731,6 +1747,10 @@ dotenv@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d" +ebnf-parser@~0.1.9: + version "0.1.10" + resolved "https://registry.yarnpkg.com/ebnf-parser/-/ebnf-parser-0.1.10.tgz#cd1f6ba477c5638c40c97ed9b572db5bab5d8331" + ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" @@ -1885,6 +1905,26 @@ 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" +escodegen@0.0.21: + version "0.0.21" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-0.0.21.tgz#53d652cfa1030388279458a5266c5ffc709c63c3" + dependencies: + esprima "~1.0.2" + estraverse "~0.0.4" + optionalDependencies: + source-map ">= 0.1.2" + +escodegen@^1.8.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852" + dependencies: + esprima "^3.1.3" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.5.6" + escope@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" @@ -1894,18 +1934,26 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" +esprima@1.0.x, esprima@~1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" + +esprima@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b" + esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esprima@^3.1.3, esprima@~3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" -esprima@~3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - esrecurse@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" @@ -1913,10 +1961,14 @@ esrecurse@^4.1.0: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" +estraverse@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-0.0.4.tgz#01a0932dfee574684a598af5a67c3bf9b6428db2" + esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2048,6 +2100,10 @@ fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + fastparse@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" @@ -2834,6 +2890,26 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" +jison-lex@0.2.x: + version "0.2.1" + resolved "https://registry.yarnpkg.com/jison-lex/-/jison-lex-0.2.1.tgz#ac4b815e8cce5132eb12b5dfcfe8d707b8844dfe" + dependencies: + lex-parser "0.1.x" + nomnom "1.5.2" + +jison@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/jison/-/jison-0.4.13.tgz#9041707d62241367f58834532b9f19c2c36fac78" + dependencies: + JSONSelect "0.4.0" + cjson "~0.2.1" + ebnf-parser "~0.1.9" + escodegen "0.0.21" + esprima "1.0.x" + jison-lex "0.2.x" + lex-parser "~0.1.3" + nomnom "1.5.2" + js-base64@^2.1.8, js-base64@^2.1.9: version "2.3.2" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf" @@ -2908,6 +2984,15 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" +jsonpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.0.0.tgz#45cd9d4c4d0d6825d90bd7e40f83f1182b13dd07" + dependencies: + esprima "1.2.2" + jison "0.4.13" + static-eval "2.0.0" + underscore "1.7.0" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -2949,6 +3034,17 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lex-parser@0.1.x, lex-parser@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/lex-parser/-/lex-parser-0.1.4.tgz#64c4f025f17fd53bfb45763faeb16f015a747550" + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -3367,6 +3463,13 @@ node-sass@^4.5.3: sass-graph "^2.1.1" stdout-stream "^1.4.0" +nomnom@1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.5.2.tgz#f4345448a853cfbd5c0d26320f2477ab0526fe2f" + dependencies: + colors "0.5.x" + underscore "1.1.x" + "nopt@2 || 3": version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -3482,6 +3585,17 @@ opn@^5.1.0: dependencies: is-wsl "^1.1.0" +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + original@>=0.0.5: version "1.0.0" resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b" @@ -3962,6 +4076,10 @@ postcss@^6.0.1, postcss@^6.0.13, postcss@^6.0.2, postcss@^6.0.6: source-map "^0.6.1" supports-color "^4.4.0" +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + prepend-http@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" @@ -4638,10 +4756,14 @@ source-map-url@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" -source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3: +source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" +"source-map@>= 0.1.2", source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + source-map@^0.1.38: version "0.1.43" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" @@ -4654,10 +4776,6 @@ source-map@^0.4.2: dependencies: amdefine ">=0.0.4" -source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" @@ -4717,6 +4835,12 @@ stack-trace@0.0.9: version "0.0.9" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" +static-eval@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.0.tgz#0e821f8926847def7b4b50cda5d55c04a9b13864" + dependencies: + escodegen "^1.8.1" + "statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" @@ -4942,6 +5066,12 @@ twitter@^1.7.1: deep-extend "^0.5.0" request "^2.72.0" +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + type-is@~1.6.15: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" @@ -4989,6 +5119,14 @@ ultron@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864" +underscore@1.1.x: + version "1.1.7" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.1.7.tgz#40bab84bad19d230096e8d6ef628bff055d83db0" + +underscore@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -5296,6 +5434,10 @@ wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"