fixes #212, fixes #210, fixes #187

This commit is contained in:
Zack Rauen 2019-06-18 22:28:48 -04:00
parent 3aebec800e
commit 89573b8d48
4 changed files with 151 additions and 67 deletions

View File

@ -38,6 +38,8 @@
"_bdhash": true, "_bdhash": true,
"ace": false, "ace": false,
"Reflect": false, "Reflect": false,
"DiscordNative": false "DiscordNative": false,
"self": "off",
"name": "off"
} }
} }

View File

@ -328,8 +328,6 @@ Core.prototype.init = async function() {
if (settingsCookie["bda-dc-0"]) document.querySelector(".btn.btn-disconnect").click(); if (settingsCookie["bda-dc-0"]) document.querySelector(".btn.btn-disconnect").click();
}); });
publicServersModule.initialize();
emoteModule.autoCapitalize(); emoteModule.autoCapitalize();
Utils.log("Startup", "Removing Loading Icon"); Utils.log("Startup", "Removing Loading Icon");
@ -829,25 +827,26 @@ EmoteModule.prototype.isCacheValid = function() {
}; };
EmoteModule.prototype.loadEmoteData = async function(emoteInfo) { EmoteModule.prototype.loadEmoteData = async function(emoteInfo) {
const _fs = require("fs"); const fs = require("fs");
const emoteFile = "emote_data.json"; const emoteFile = "emote_data.json";
const file = bdConfig.dataPath + emoteFile; const file = bdConfig.dataPath + emoteFile;
const exists = _fs.existsSync(file); const exists = await new Promise(r => fs.exists(file, r));
if (exists && this.isCacheValid()) { if (exists && this.isCacheValid()) {
if (settingsCookie["fork-ps-2"]) mainCore.showToast("Loading emotes from cache.", {type: "info"}); if (settingsCookie["fork-ps-2"]) mainCore.showToast("Loading emotes from cache.", {type: "info"});
Utils.log("Emotes", "Loading emotes from local cache."); Utils.log("Emotes", "Loading emotes from local cache.");
const data = await new Promise(resolve => { const data = await new Promise(resolve => {
_fs.readFile(file, "utf8", (err, data) => { fs.readFile(file, "utf8", (err, data) => {
Utils.log("Emotes", "Emotes loaded from cache."); Utils.log("Emotes", "Emote file read.");
if (err) data = {}; if (err) data = {};
resolve(data); resolve(data);
}); });
}); });
let isValid = Utils.testJSON(data); const parsed = Utils.testJSON(data);
if (isValid) window.bdEmotes = JSON.parse(data); let isValid = !!parsed;
if (isValid) window.bdEmotes = parsed;
for (const e in emoteInfo) { for (const e in emoteInfo) {
isValid = Object.keys(window.bdEmotes[emoteInfo[e].variable]).length > 0; isValid = Object.keys(window.bdEmotes[emoteInfo[e].variable]).length > 0;
@ -859,7 +858,7 @@ EmoteModule.prototype.loadEmoteData = async function(emoteInfo) {
} }
Utils.log("Emotes", "Cache was corrupt, downloading..."); Utils.log("Emotes", "Cache was corrupt, downloading...");
_fs.unlinkSync(file); await new Promise(r => fs.unlink(file, r));
} }
if (!settingsCookie["fork-es-3"]) return; if (!settingsCookie["fork-es-3"]) return;
@ -873,7 +872,7 @@ EmoteModule.prototype.loadEmoteData = async function(emoteInfo) {
if (settingsCookie["fork-ps-2"]) mainCore.showToast("All emotes successfully downloaded.", {type: "success"}); if (settingsCookie["fork-ps-2"]) mainCore.showToast("All emotes successfully downloaded.", {type: "success"});
try { _fs.writeFileSync(file, JSON.stringify(window.bdEmotes), "utf8"); } try { await new Promise(r => fs.writeFile(file, JSON.stringify(window.bdEmotes), "utf8", r)); }
catch (err) { Utils.err("Emotes", "Could not save emote data.", err); } catch (err) { Utils.err("Emotes", "Could not save emote data.", err); }
}; };
@ -881,13 +880,14 @@ EmoteModule.prototype.downloadEmotes = function(emoteMeta) {
let request = require("request"); let request = require("request");
let options = { let options = {
url: emoteMeta.url, url: emoteMeta.url,
timeout: emoteMeta.timeout ? emoteMeta.timeout : 5000 timeout: emoteMeta.timeout ? emoteMeta.timeout : 5000,
json: true
}; };
Utils.log("Emotes", `Downloading: ${emoteMeta.variable} (${emoteMeta.url})`); Utils.log("Emotes", `Downloading: ${emoteMeta.variable} (${emoteMeta.url})`);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request(options, (error, response, body) => { request(options, (error, response, parsedData) => {
if (error) { if (error) {
Utils.err("Emotes", "Could not download " + emoteMeta.variable, error); Utils.err("Emotes", "Could not download " + emoteMeta.variable, error);
if (emoteMeta.backup) { if (emoteMeta.backup) {
@ -899,20 +899,6 @@ EmoteModule.prototype.downloadEmotes = function(emoteMeta) {
return reject({}); return reject({});
} }
let parsedData = {};
try {
parsedData = JSON.parse(body);
}
catch (err) {
Utils.err("Emotes", "Could not download " + emoteMeta.variable, err);
if (emoteMeta.backup) {
emoteMeta.url = emoteMeta.backup;
emoteMeta.backup = null;
if (emoteMeta.backupParser) emoteMeta.parser = emoteMeta.backupParser;
return resolve(this.downloadEmotes(emoteMeta));
}
return reject({});
}
if (typeof(emoteMeta.parser) === "function") parsedData = emoteMeta.parser(parsedData); if (typeof(emoteMeta.parser) === "function") parsedData = emoteMeta.parser(parsedData);
for (let emote in parsedData) { for (let emote in parsedData) {
@ -1209,7 +1195,7 @@ var Utils = class {
} }
static escapeID(id) { static escapeID(id) {
return id.replace(/^[^a-z]+|[^\w-]+/gi, ""); return id.replace(/^[^a-z]+|[^\w-]+/gi, "-");
} }
static log(moduleName, message) { static log(moduleName, message) {
@ -1235,14 +1221,23 @@ var Utils = class {
static testJSON(data) { static testJSON(data) {
try { try {
JSON.parse(data); return JSON.parse(data);
return true;
} }
catch (err) { catch (err) {
return false; return false;
} }
} }
static isEmpty(obj) {
if (obj == null || obj == undefined || obj == "") return true;
if (typeof(obj) !== "object") return false;
if (Array.isArray(obj)) return obj.length == 0;
for (const key in obj) {
if (obj.hasOwnProperty(key)) return false;
}
return true;
}
static suppressErrors(method, message) { static suppressErrors(method, message) {
return (...params) => { return (...params) => {
try { return method(...params); } try { return method(...params); }
@ -1359,7 +1354,8 @@ var ContentManager = (() => {
} }
const originalJSRequire = Module._extensions[".js"]; const originalJSRequire = Module._extensions[".js"];
const originalCSSRequire = Module._extensions[".css"] ? Module._extensions[".css"] : () => {return null;}; const originalCSSRequire = Module._extensions[".css"] ? Module._extensions[".css"] : () => {return null;};
const splitRegex = /[^\S\r\n]*?\n[^\S\r\n]*?\*[^\S\r\n]?/;
const escapedAtRegex = /^\\@/;
return new class ContentManager { return new class ContentManager {
@ -1413,15 +1409,47 @@ var ContentManager = (() => {
} }
extractMeta(content) { extractMeta(content) {
const firstLine = content.split("\n")[0];
const hasOldMeta = firstLine.includes("//META");
if (hasOldMeta) return this.parseOldMeta(content);
const hasNewMeta = firstLine.includes("/**");
if (hasNewMeta) return this.parseNewMeta(content);
throw new MetaError("META was not found.");
}
parseOldMeta(content) {
const meta = content.split("\n")[0]; const meta = content.split("\n")[0];
const rawMeta = meta.substring(meta.lastIndexOf("//META") + 6, meta.lastIndexOf("*//")); const rawMeta = meta.substring(meta.lastIndexOf("//META") + 6, meta.lastIndexOf("*//"));
if (meta.indexOf("META") < 0) throw new MetaError("META was not found."); if (meta.indexOf("META") < 0) throw new MetaError("META was not found.");
if (!Utils.testJSON(rawMeta)) throw new MetaError("META could not be parsed."); const parsed = Utils.testJSON(rawMeta);
if (!parsed) throw new MetaError("META could not be parsed.");
const parsed = JSON.parse(rawMeta);
if (!parsed.name) throw new MetaError("META missing name data."); if (!parsed.name) throw new MetaError("META missing name data.");
return parsed; return parsed;
} }
parseNewMeta(content) {
const block = content.split("/**", 2)[1].split("*/", 1)[0];
const out = {};
let field = "";
let accum = "";
for (const line of block.split(splitRegex)) {
if (line.length === 0) continue;
if (line.charAt(0) === "@" && line.charAt(1) !== " ") {
out[field] = accum;
const l = line.indexOf(" ");
field = line.substr(1, l - 1);
accum = line.substr(l + 1);
}
else {
accum += " " + line.replace("\\n", "\n").replace(escapedAtRegex, "@");
}
}
out[field] = accum.trim();
delete out[""];
return out;
}
getContentRequire(type) { getContentRequire(type) {
const isPlugin = type === "plugin"; const isPlugin = type === "plugin";
@ -1441,7 +1469,16 @@ var ContentManager = (() => {
content = `module.exports = ${JSON.stringify(meta)};`; content = `module.exports = ${JSON.stringify(meta)};`;
} }
if (isPlugin) { if (isPlugin) {
content += `\nmodule.exports = ${JSON.stringify(meta)};\nmodule.exports.type = ${meta.name};`; module._compile(content, module.filename);
const didExport = !Utils.isEmpty(module.exports);
if (didExport) {
meta.type = module.exports;
module.exports = meta;
content = "";
}
else {
content += `\nmodule.exports = ${JSON.stringify(meta)};\nmodule.exports.type = ${meta.exports || meta.name};`;
}
} }
module._compile(content, filename); module._compile(content, filename);
}; };
@ -1469,6 +1506,7 @@ var ContentManager = (() => {
try {require(path.resolve(baseFolder, filename));} try {require(path.resolve(baseFolder, filename));}
catch (error) {return {name: filename, file: filename, message: "Could not be compiled.", error: {message: error.message, stack: error.stack}};} catch (error) {return {name: filename, file: filename, message: "Could not be compiled.", error: {message: error.message, stack: error.stack}};}
const content = require(path.resolve(baseFolder, filename)); const content = require(path.resolve(baseFolder, filename));
content.id = Utils.escapeID(content.name);
if (isPlugin) { if (isPlugin) {
if (!content.type) return; if (!content.type) return;
try { try {
@ -1600,7 +1638,7 @@ PluginModule.prototype.startPlugin = function(plugin, reload = false) {
if (settingsCookie["fork-ps-2"] && !reload) mainCore.showToast(`${bdplugins[plugin].plugin.getName()} v${bdplugins[plugin].plugin.getVersion()} could not be started.`, {type: "error"}); if (settingsCookie["fork-ps-2"] && !reload) mainCore.showToast(`${bdplugins[plugin].plugin.getName()} v${bdplugins[plugin].plugin.getVersion()} could not be started.`, {type: "error"});
pluginCookie[plugin] = false; pluginCookie[plugin] = false;
this.savePluginData(); this.savePluginData();
Utils.err("Plugins", name + " could not be started.", err); Utils.err("Plugins", plugin + " could not be started.", err);
} }
}; };
@ -1758,9 +1796,9 @@ ThemeModule.prototype.loadThemes = function () {
var themes = Object.keys(bdthemes); var themes = Object.keys(bdthemes);
for (var i = 0; i < themes.length; i++) { for (var i = 0; i < themes.length; i++) {
var name = bdthemes[themes[i]].name; var theme = bdthemes[themes[i]];
if (!themeCookie[name]) themeCookie[name] = false; if (!themeCookie[theme.name]) themeCookie[theme.name] = false;
if (themeCookie[name]) $("head").append($("<style>", {id: Utils.escapeID(name), text: unescape(bdthemes[name].css)})); if (themeCookie[theme.name]) $("head").append($("<style>", {id: theme.id, text: unescape(theme.css)}));
} }
for (let theme in themeCookie) { for (let theme in themeCookie) {
if (!bdthemes[theme]) delete themeCookie[theme]; if (!bdthemes[theme]) delete themeCookie[theme];
@ -1769,18 +1807,20 @@ ThemeModule.prototype.loadThemes = function () {
// if (settingsCookie["fork-ps-5"]) ContentManager.watchContent("theme"); // if (settingsCookie["fork-ps-5"]) ContentManager.watchContent("theme");
}; };
ThemeModule.prototype.enableTheme = function(theme, reload = false) { ThemeModule.prototype.enableTheme = function(name, reload = false) {
themeCookie[theme] = true; themeCookie[name] = true;
this.saveThemeData(); this.saveThemeData();
$("head").append($("<style>", {id: Utils.escapeID(theme), text: unescape(bdthemes[theme].css)})); const theme = bdthemes[name];
if (settingsCookie["fork-ps-2"] && !reload) mainCore.showToast(`${bdthemes[theme].name} v${bdthemes[theme].version} has been applied.`); $("head").append($("<style>", {id: theme.id, text: unescape(theme.css)}));
if (settingsCookie["fork-ps-2"] && !reload) mainCore.showToast(`${theme.name} v${theme.version} has been applied.`);
}; };
ThemeModule.prototype.disableTheme = function(theme, reload = false) { ThemeModule.prototype.disableTheme = function(name, reload = false) {
themeCookie[theme] = false; themeCookie[name] = false;
this.saveThemeData(); this.saveThemeData();
$(`#${Utils.escapeID(bdthemes[theme].name)}`).remove(); const theme = bdthemes[name];
if (settingsCookie["fork-ps-2"] && !reload) mainCore.showToast(`${bdthemes[theme].name} v${bdthemes[theme].version} has been disabled.`); $(`#${theme.id}`).remove();
if (settingsCookie["fork-ps-2"] && !reload) mainCore.showToast(`${theme.name} v${theme.version} has been disabled.`);
}; };
ThemeModule.prototype.toggleTheme = function(theme) { ThemeModule.prototype.toggleTheme = function(theme) {
@ -1871,7 +1911,7 @@ var BdApi = {
const path = require("path"); const path = require("path");
const base = electron.getAppPath(); const base = electron.getAppPath();
const roamingBase = electron.getPath("userData"); const roamingBase = electron.getPath("userData");
const roamingLocation = path.resolve(roamingBase, electron.getVersion(), "modules", "discord_desktop_core", "injector", "config.json") const roamingLocation = path.resolve(roamingBase, electron.getVersion(), "modules", "discord_desktop_core", "injector", "config.json");
const location = path.resolve(base, "..", "app", "config.json"); const location = path.resolve(base, "..", "app", "config.json");
const fs = require("fs"); const fs = require("fs");
const realLocation = fs.existsSync(location) ? location : fs.existsSync(roamingLocation) ? roamingLocation : null; const realLocation = fs.existsSync(location) ? location : fs.existsSync(roamingLocation) ? roamingLocation : null;
@ -2173,7 +2213,10 @@ BdApi.setBDData = function(key, data) {
devMode.prototype.getRules = function(element, css = element.ownerDocument.styleSheets) { devMode.prototype.getRules = function(element, css = element.ownerDocument.styleSheets) {
//if (window.getMatchedCSSRules) return window.getMatchedCSSRules(element); //if (window.getMatchedCSSRules) return window.getMatchedCSSRules(element);
return [].concat(...[...css].map(s => [...s.cssRules || []])).filter(r => r && r.selectorText && element.matches(r.selectorText) && r.style.length && r.selectorText.split(", ").length < 8); const sheets = [...css].filter(s => !s.href || !s.href.includes("BetterDiscordApp"));
const rules = sheets.map(s => [...(s.cssRules || [])]).flat();
const elementRules = rules.filter(r => r && r.selectorText && element.matches(r.selectorText) && r.style.length && r.selectorText.split(", ").length < 8 && !r.selectorText.split(", ").includes("*"));
return elementRules;
}; };
devMode.prototype.getSelector = function(element) { devMode.prototype.getSelector = function(element) {
@ -4085,8 +4128,8 @@ class V2_SettingsPanel {
} }
if (id == "bda-gs-1") { if (id == "bda-gs-1") {
if (enabled) $("#bd-pub-li").show(); if (enabled) publicServersModule.addButton();
else $("#bd-pub-li").hide(); else publicServersModule.removeButton();
} }
if (id == "bda-gs-4") { if (id == "bda-gs-4") {
@ -4144,6 +4187,10 @@ class V2_SettingsPanel {
else dMode.disable(); else dMode.disable();
} }
if (id == "fork-dm-1") {
if (settingsCookie["bda-gs-8"]) dMode.enable(enabled);
}
mainCore.saveSettings(); mainCore.saveSettings();
} }
@ -4152,7 +4199,7 @@ class V2_SettingsPanel {
// if (settingsCookie["bda-gs-b"]) $("body").addClass("bd-blue"); // if (settingsCookie["bda-gs-b"]) $("body").addClass("bd-blue");
if (settingsCookie["bda-gs-2"]) $("body").addClass("bd-minimal"); if (settingsCookie["bda-gs-2"]) $("body").addClass("bd-minimal");
if (settingsCookie["bda-gs-3"]) $("body").addClass("bd-minimal-chan"); if (settingsCookie["bda-gs-3"]) $("body").addClass("bd-minimal-chan");
if (settingsCookie["bda-gs-1"]) $("#bd-pub-li").show(); if (settingsCookie["bda-gs-1"]) publicServersModule.addButton();
if (settingsCookie["bda-gs-4"]) voiceMode.enable(); if (settingsCookie["bda-gs-4"]) voiceMode.enable();
if (settingsCookie["bda-gs-5"]) $("#app-mount").addClass("bda-dark"); if (settingsCookie["bda-gs-5"]) $("#app-mount").addClass("bda-dark");
if (settingsCookie["bda-gs-6"]) mainCore.inject24Hour(); if (settingsCookie["bda-gs-6"]) mainCore.inject24Hour();
@ -4439,7 +4486,9 @@ class V2C_SidebarView extends BDV2.reactComponent {
class V2_PublicServers { class V2_PublicServers {
constructor() {} constructor() {
this._appendButton = this._appendButton.bind(this);
}
get component() { get component() {
return BDV2.react.createElement(V2Components.Layer, {rootId: "pubslayerroot", id: "pubslayer", children: BDV2.react.createElement(V2C_PublicServers, {rootId: "pubslayerroot"})}); return BDV2.react.createElement(V2Components.Layer, {rootId: "pubslayerroot", id: "pubslayer", children: BDV2.react.createElement(V2C_PublicServers, {rootId: "pubslayerroot"})});
@ -4487,11 +4536,25 @@ class V2_PublicServers {
return btn; return btn;
} }
initialize() { _appendButton() {
if ($("#bd-pub-li").length) return;
const wrapper = BDV2.guildClasses.wrapper.split(" ")[0]; const wrapper = BDV2.guildClasses.wrapper.split(" ")[0];
const guilds = $(`.${wrapper} .scroller-2FKFPG >:first-child`); const guilds = $(`.${wrapper} .scroller-2FKFPG >:first-child`);
guilds.after(this.button); guilds.after(this.button);
} }
addButton() {
if (this.guildPatch) return;
const GuildList = BdApi.findModuleByDisplayName("Guilds");
this.guildPatch = BdApi.monkeyPatch(GuildList.prototype, "render", {after: this._appendButton});
this._appendButton();
}
removeButton() {
this.guildPatch();
delete this.guildPatch;
$("#bd-pub-li").remove();
}
} }

4
js/main.min.js vendored

File diff suppressed because one or more lines are too long

41
package-lock.json generated
View File

@ -1550,7 +1550,8 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -1571,12 +1572,14 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -1591,17 +1594,20 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -1718,7 +1724,8 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -1730,6 +1737,7 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -1744,6 +1752,7 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -1751,12 +1760,14 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -1775,6 +1786,7 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -1855,7 +1867,8 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -1867,6 +1880,7 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -1952,7 +1966,8 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -1988,6 +2003,7 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -2007,6 +2023,7 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -2050,12 +2067,14 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
} }
} }
}, },