diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..76137027 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,12 @@ +{ + "extends": ["eslint:recommended", "semistandard", "prettier"], + "parser": "babel-eslint", + "rules": { + "no-throw-literal": 0, + "no-console": "off", + "semi": 1 + }, + "env": { + "browser": true + } +} diff --git a/app/application.js b/app/application.js new file mode 100644 index 00000000..d70de482 --- /dev/null +++ b/app/application.js @@ -0,0 +1,296 @@ +import { + ArchiveManager, + ExtensionsServer, + MenuManager, + PackageManager, + SearchManager, + TrayManager, + UpdateManager, + ZoomManager +} from './javascripts/main'; +import { + Store, + StoreKeys +} from './javascripts/main/store'; + +const { app, BrowserWindow, shell, ipcMain } = require('electron'); +const path = require('path'); +const windowStateKeeper = require('electron-window-state'); + +const APPLICATION_NAME = 'Standard Notes'; +const WINDOW_DEFAULT_WIDTH = 1100; +const WINDOW_DEFAULT_HEIGHT = 800; +const WINDOW_MIN_WIDTH = 300; +const WINDOW_MIN_HEIGHT = 400; + +const Platforms = { + Mac: 1, + Windows: 2, + Linux: 3, + isMac: (platform) => { + return platform === Platforms.Mac; + }, +}; + +export class DesktopApplication { + + static instance = null; + + static createSharedApplication() { + const getPlatform = () => { + const processPlatform = process.platform; + if (processPlatform === 'darwin') { + return Platforms.Mac; + } else if (processPlatform === 'win32') { + return Platforms.Windows; + } else if (processPlatform === 'linux') { + return Platforms.Linux; + } + }; + this.instance = new DesktopApplication({ + platform: getPlatform() + }); + } + + static sharedApplication() { + if (!this.instance) { + throw 'Attempting to access application before creation'; + } + return this.instance; + } + + constructor({ + platform + }) { + this.platform = platform; + this.isMac = Platforms.isMac(this.platform); + app.setName(APPLICATION_NAME); + this.createExtensionsServer(); + this.registerAppEventListeners(); + this.registerSingleInstanceHandler(); + this.registerIpcEventListeners(); + } + + createExtensionsServer() { + this.extensionsServer = new ExtensionsServer(); + Store.set(StoreKeys.ExtServerHost, this.extensionsServer.getHost()); + } + + onWindowCreate() { + this.createServices(); + } + + createServices() { + this.archiveManager = new ArchiveManager(this.window); + this.packageManager = new PackageManager(this.window); + this.searchManager = new SearchManager(this.window); + this.trayManager = new TrayManager(this.window); + this.updateManager = new UpdateManager(this.window); + this.zoomManager = new ZoomManager(this.window); + this.menuManager = new MenuManager( + this.window, + this.archiveManager, + this.updateManager, + this.trayManager + ); + } + + registerSingleInstanceHandler() { + const hasRequestSingleInstanceLock = app.requestSingleInstanceLock ? true : false; + /* Someone tried to run a second instance, we should focus our window. */ + const handleSecondInstance = (argv, cwd) => { + if (this.window) { + if (!this.window.isVisible()) { + this.window.show(); + } + if (this.window.isMinimized()) { + this.window.restore(); + } + this.window.focus(); + } + }; + + if (hasRequestSingleInstanceLock) { + this.isSecondInstance = !app.requestSingleInstanceLock(); + app.on('second-instance', (event, argv, cwd) => { + handleSecondInstance(argv, cwd); + }); + } else { + this.isSecondInstance = app.makeSingleInstance((argv, cwd) => { + handleSecondInstance(argv, cwd); + }); + } + } + + registerIpcEventListeners() { + ipcMain.on("display-app-menu", (event, position) => { + this.menuManager.popupMenu(position); + }); + + ipcMain.on('initial-data-loaded', () => { + this.archiveManager.beginBackups(); + }); + + ipcMain.on('major-data-change', () => { + this.archiveManager.performBackup(); + }); + } + + registerAppEventListeners() { + app.on('window-all-closed', () => { + if (!this.isMac) { + app.quit(); + } + }); + + app.on('before-quit', () => { + this.willQuitApp = true; + }); + + app.on('activate', () => { + if (!this.window) { + this.createWindow(); + } else { + this.window.show(); + } + this.updateManager.checkForUpdate(); + }); + + app.on('ready', () => { + if (this.isSecondInstance) { + console.warn("Quiting app and focusing existing instance."); + app.quit(); + } else { + if (!this.window) { + this.createWindow(); + } else { + this.window.focus(); + } + + this.menuManager.loadMenu(); + this.updateManager.onNeedMenuReload = () => { + this.menuManager.reload(); + }; + + const isWindowsOrLinux = + this.platform === Platforms.Windows || + this.platform === Platforms.Linux; + if (isWindowsOrLinux && this.trayManager.shouldMinimizeToTray()) { + this.trayManager.createTrayIcon(); + } + } + }); + } + + createWindow() { + const winState = windowStateKeeper({ + defaultWidth: WINDOW_DEFAULT_WIDTH, + defaultHeight: WINDOW_DEFAULT_HEIGHT + }); + const iconLocation = path.join(__dirname, '/icon/Icon-512x512.png'); + const useSystemMenuBar = Store.get(StoreKeys.useSystemMenuBar); + const titleBarStyle = (this.isMac || useSystemMenuBar) + ? 'hiddenInset' + : null; + this.window = new BrowserWindow({ + 'x': winState.x, + 'y': winState.y, + 'width': winState.width, + 'height': winState.height, + 'minWidth': WINDOW_MIN_WIDTH, + 'minHeight': WINDOW_MIN_HEIGHT, + show: false, + icon: iconLocation, + titleBarStyle: titleBarStyle, + frame: this.isMac ? false : useSystemMenuBar, + webPreferences: { + nodeIntegration: false, + contextIsolation: true, + preload: path.join(__dirname, "javascripts/renderer/preload.js") + } + }); + + winState.manage(this.window); + this.onWindowCreate(); + + this.window.on('closed', (event) => { + this.window = null; + }); + + this.window.on('blur', (event) => { + this.window.webContents.send("window-blurred", null); + this.archiveManager.applicationDidBlur(); + }); + + this.window.on('focus', (event) => { + this.window.webContents.send("window-focused", null); + }); + + this.window.once('ready-to-show', () => { + this.window.show(); + }); + + this.window.on('close', (event) => { + if (this.willQuitApp) { + /* The user tried to quit the app */ + this.window = null; + } else if (this.isMac || this.trayManager.shouldMinimizeToTray()) { + /* The user only tried to close the window */ + event.preventDefault(); + /* Handles Mac full screen issue where pressing close results in a black screen. */ + if (this.window.isFullScreen()) { + this.window.setFullScreen(false); + } + this.window.hide(); + } + }); + + let windowUrl = path.join('file://', __dirname, '/index.html'); + if ('APP_RELATIVE_PATH' in process.env) { + windowUrl = path.join('file://', __dirname, process.env.APP_RELATIVE_PATH); + } + this.window.loadURL(windowUrl); + + const shouldOpenUrl = (url) => { + return url.startsWith("http") || url.startsWith("https"); + }; + // Check file urls for equality by decoding components + // In packaged app, spaces in navigation events urls can contain %20 but not in windowUrl. + const safeFileUrlCompare = (a, b) => { + // Catch exceptions in case of malformed urls. + try { + // Craft URL objects to eliminate production URL values that can contain "#!/" suffixes (on Windows) + const aPath = new URL(decodeURIComponent(a)).pathname; + const bPath = new URL(decodeURIComponent(b)).pathname; + return aPath === bPath; + } catch (error) { + return false; + } + }; + + // handle link clicks + this.window.webContents.on('new-window', (event, url) => { + if (shouldOpenUrl(url)) { + shell.openExternal(url); + } + event.preventDefault(); + }); + + // handle link clicks (this event is fired instead of + // 'new-window' when target is not set to _blank) + this.window.webContents.on('will-navigate', (event, url) => { + // Check for windowUrl equality in the case of window.reload() calls. + if (safeFileUrlCompare(url, windowUrl) === true) { + return; + } + if (shouldOpenUrl(url)) { + shell.openExternal(url); + } + event.preventDefault(); + }); + } + + openDevTools() { + this.window.webContents.openDevTools(); + } +} \ No newline at end of file diff --git a/app/index.html b/app/index.html index c7bef70e..9b63f193 100644 --- a/app/index.html +++ b/app/index.html @@ -1,44 +1,69 @@ - + - - - - - - + + + - - + + + - - - + + - - - + + + - -
-
- -
-
- - - -
+ + + + + +
+
+ +
+
+ + +
- - +
+ + - + \ No newline at end of file diff --git a/app/index.js b/app/index.js index 37dc6a80..d80fde39 100644 --- a/app/index.js +++ b/app/index.js @@ -1,240 +1,10 @@ -const {app, BrowserWindow, ipcMain, session} = require('electron'); -app.setName('Standard Notes'); +import { DesktopApplication } from './application'; -const path = require('path') -const windowStateKeeper = require('electron-window-state') -const shell = require('electron').shell; -const log = require('electron-log'); -const Store = require('./javascripts/main/store.js'); - -const ExtensionsServer = require('./javascripts/main/extServer.js'); -ExtensionsServer.instance().createServer(); - -import menuManager from './javascripts/main/menuManager.js' -import archiveManager from './javascripts/main/archiveManager.js'; -import packageManager from './javascripts/main/packageManager.js'; -import searchManager from './javascripts/main/searchManager.js'; -import updateManager from './javascripts/main/updateManager.js'; -import zoomManager from './javascripts/main/zoomManager.js'; -import trayManager from './javascripts/main/trayManager.js'; - -ipcMain.on('initial-data-loaded', () => { - archiveManager.beginBackups(); -}); - -ipcMain.on('major-data-change', () => { - archiveManager.performBackup(); -}) - -process.on('uncaughtException', function (err) { - console.log(err); -}) +DesktopApplication.createSharedApplication(); +const log = require('electron-log'); log.transports.file.level = 'info'; -let darwin = process.platform === 'darwin' -let win, willQuitApp = false; - -// Quit when all windows are closed. -app.on('window-all-closed', () => { - // On macOS it is common for applications and their menu bar - // to stay active until the user quits explicitly with Cmd + Q - if (!darwin) { - app.quit() - } -}) - -function createWindow () { - // Load the previous state with fallback to defaults - let winState = windowStateKeeper({ - defaultWidth: 1100, - defaultHeight: 800 - }) - - let iconLocation = path.join(__dirname, '/icon/Icon-512x512.png'); - - // Defaults to false in store.js - let useSystemMenuBar = Store.instance().get("useSystemMenuBar"); - - // Create the window using the state information - win = new BrowserWindow({ - 'x': winState.x, - 'y': winState.y, - 'width': winState.width, - 'height': winState.height, - 'minWidth': 300, - 'minHeight': 400, - show: false, - icon: iconLocation, - - // We want hiddenInset on Mac. On Windows/Linux, doesn't seem to have an effect, but we'll default to it's original value before themed title bar changes were put in place. - titleBarStyle: darwin || useSystemMenuBar ? 'hiddenInset' : null, - - // Will apply to Windows and Linux only, since titleBarStyle takes precendence for mac. But we'll explicitely specifiy false for mac to be on the safe side - frame: darwin ? false : useSystemMenuBar, - - webPreferences: { - nodeIntegration: false, - contextIsolation: true, - preload: path.join(__dirname, "javascripts/renderer/preload.js") - } - }) - - searchManager.setWindow(win); - archiveManager.setWindow(win); - packageManager.setWindow(win); - updateManager.setWindow(win); - zoomManager.setWindow(win); - trayManager.setWindow(win); - - // Register listeners on the window, so we can update the state - // automatically (the listeners will be removed when the window - // is closed) and restore the maximized or full screen state - winState.manage(win) - // win.webContents.openDevTools() - - win.on('closed', (event) => { - win = null - }) - - win.on('blur', (event) => { - win.webContents.send("window-blurred", null); - archiveManager.applicationDidBlur(); - }) - - win.on('focus', (event) => { - win.webContents.send("window-focused", null); - }) - - win.once('ready-to-show', () => { - win.show() - }) - - win.on('close', (event) => { - if (willQuitApp) { - /* the user tried to quit the app */ - win = null; - } else if(darwin || trayManager.shouldMinimizeToTray()) { - /* the user only tried to close the window */ - event.preventDefault(); - - // Fixes Mac full screen issue where pressing close results in a black screen. - if(win.isFullScreen()) { - win.setFullScreen(false); - } - win.hide(); - } - }) - - let windowUrl = 'file://' + __dirname + '/index.html'; - if ('APP_RELATIVE_PATH' in process.env) { - windowUrl = 'file://' + __dirname + '/' + process.env.APP_RELATIVE_PATH; - } - win.loadURL(windowUrl); - - const shouldOpenUrl = (url) => { - return url.startsWith("http") || url.startsWith("https"); - } - - // Check file urls for equality by decoding components - // In packaged app, spaces in navigation events urls can contain %20 but not in windowUrl. - const safeFileUrlCompare = (a, b) => { - // Catch exceptions in case of malformed urls. - try { - // Craft URL objects to eliminate production URL values that can contain "#!/" suffixes (on Windows) - let aPath = new URL(decodeURIComponent(a)).pathname; - let bPath = new URL(decodeURIComponent(b)).pathname; - return aPath === bPath; - } catch (error) { - return false; - } - } - - // handle link clicks - win.webContents.on('new-window', function(event, url) { - if(shouldOpenUrl(url)) { - shell.openExternal(url); - } - event.preventDefault(); - }); - - // handle link clicks (this event is fired instead of - // 'new-window' when target is not set to _blank) - win.webContents.on('will-navigate', function(event, url) { - // Check for windowUrl equality in the case of window.reload() calls. - if(safeFileUrlCompare(url, windowUrl) === true) { - return; - } - - if(shouldOpenUrl(url)) { - shell.openExternal(url); - } - - event.preventDefault(); - }); -} - -app.on('before-quit', () => willQuitApp = true); - -app.on('activate', function() { - - if (!win) { - createWindow(); - } else { - win.show(); - } - - updateManager.checkForUpdate(); -}); - -// feature flag: https://github.com/electron/electron/blob/master/docs/api/breaking-changes.md#appmakesingleinstance -const hasRequestSingleInstanceLock = app.requestSingleInstanceLock ? true : false; -let isSecondInstance = null; - -// Someone tried to run a second instance, we should focus our window. -const handleSecondInstance = (argv, cwd) => { - if (win) { - if (!win.isVisible()) win.show(); - if (win.isMinimized()) win.restore(); - win.focus(); - } -} - -if (hasRequestSingleInstanceLock) { - isSecondInstance = !app.requestSingleInstanceLock() - - app.on('second-instance', (event, argv, cwd) => { - handleSecondInstance(argv, cwd) - }) -} else { - isSecondInstance = app.makeSingleInstance((argv, cwd) => { - handleSecondInstance(argv, cwd) - }) -} - -app.on('ready', function(){ - if (isSecondInstance) { - console.warn("Quiting app and focusing existing instance."); - app.quit() - } else { - if(!win) { - createWindow(); - } else { - win.focus(); - } - - menuManager.loadMenu(win, archiveManager, updateManager, trayManager); - updateManager.onNeedMenuReload = () => { - menuManager.reload(); - } - - if (trayManager.shouldMinimizeToTray() && (process.platform === 'win32' || process.platform === 'linux')) { - trayManager.createTrayIcon(); - } - } - -}) - -ipcMain.on("display-app-menu", (event, position) => { - menuManager.popupMenu(position); +process.on('uncaughtException', function (err) { + console.error('Uncaught exception', err); }); diff --git a/app/javascripts/main/archiveManager.js b/app/javascripts/main/archiveManager.js index b03b1827..036877af 100644 --- a/app/javascripts/main/archiveManager.js +++ b/app/javascripts/main/archiveManager.js @@ -1,21 +1,18 @@ -var {ipcMain, remote, dialog, app} = require('electron'); +import { Store, StoreKeys } from './store'; +const {ipcMain, dialog, app} = require('electron'); var fs = require('fs'); var path = require('path'); -const Store = require('./store.js'); - -const store = Store.instance(); - -class ArchiveManager { - - constructor() { +export class ArchiveManager { + constructor(window) { + this.window = window; ipcMain.on('data-archive', (event, data) => { this.writeDataToFile(data, (success) => { this.window.webContents.send("finished-saving-backup", {success: success}); }); }); - this.backupsLocation = store.get("backupsLocation"); - this.backupsDisabled = store.get("backupsDisabled"); + this.backupsLocation = Store.get(StoreKeys.BackupsLocation); + this.backupsDisabled = Store.get(StoreKeys.BackupsDisabled); } applicationDidBlur() { @@ -40,22 +37,22 @@ class ArchiveManager { dialog.showOpenDialog({ properties: ['openDirectory', 'showHiddenFiles', 'createDirectory'] }, (paths) => { - let path = paths[0]; + const path = paths[0]; this.backupsLocation = path; - store.set("backupsLocation", path); + Store.set(StoreKeys.BackupsLocation, path); this.performBackup(); - }) + }); } writeDataToFile(data, callback) { if(this.backupsDisabled) { - console.log("Backups are disabled; returning.") + console.log("Backups are disabled; returning."); return; } // We want to create this directory, even if data is empty, // just so it's there and the user can open it. - let dir = this.getBackupsLocation(); + const dir = this.getBackupsLocation(); if (!fs.existsSync(dir)){ fs.mkdirSync(dir); } @@ -74,7 +71,7 @@ class ArchiveManager { fs.writeFile(filePath, data, (err) => { if(err){ - console.log("An error ocurred saving backup file: " + err.message) + console.log("An error ocurred saving backup file: " + err.message); } else { console.log("Data backup succesfully saved: ", name); } @@ -82,10 +79,6 @@ class ArchiveManager { }); } - setWindow(window) { - this.window = window; - } - beginBackups() { if(this.interval) { clearInterval(this.interval); @@ -94,10 +87,9 @@ class ArchiveManager { // Instead of performing a backup on app launch, // which drastically slows down performance, wait until window blurs this.needsBackup = true; - - let hoursInterval = 12; // Every X hours - let seconds = hoursInterval * 60 * 60; - let milliseconds = seconds * 1000; + const hoursInterval = 12; // Every X hours + const seconds = hoursInterval * 60 * 60; + const milliseconds = seconds * 1000; this.interval = setInterval(() => { this.performBackup(); }, milliseconds); @@ -105,7 +97,7 @@ class ArchiveManager { performBackup() { if(this.backupsDisabled) { - console.log("Backups are disabled; returning.") + console.log("Backups are disabled; returning."); return; } this.window.webContents.send("download-backup"); @@ -117,9 +109,6 @@ class ArchiveManager { toggleBackupsStatus() { this.backupsDisabled = !this.backupsDisabled; - store.set("backupsDisabled", this.backupsDisabled); + Store.set(StoreKeys.BackupsDisabled, this.backupsDisabled); } - } - -export default new ArchiveManager(); diff --git a/app/javascripts/main/extServer.js b/app/javascripts/main/extServer.js index b0946328..e3b59fb6 100644 --- a/app/javascripts/main/extServer.js +++ b/app/javascripts/main/extServer.js @@ -1,33 +1,14 @@ -const {app} = require('electron'); +const { app } = require('electron'); const http = require('http'); const fs = require('fs'); const path = require('path'); const mime = require('mime-types'); const url = require('url'); -const mimes = { - '.ico': 'image/x-icon', - '.html': 'text/html', - '.js': 'text/javascript', - '.json': 'application/json', - '.css': 'text/css', - '.png': 'image/png', - '.jpg': 'image/jpeg' -}; - -let instance = null; - -class ExtensionsServer { - - static instance() { - if(instance == null) { - instance = new ExtensionsServer(); - } - return instance; - } - +export class ExtensionsServer { constructor() { this.port = 45653; + this.createServer(); } getHost() { @@ -43,8 +24,8 @@ class ExtensionsServer { const modifiedReqUrl = path.normalize(pathName.replace(extensionsFolder, "")); const filePath = path.join(extensionsDir, modifiedReqUrl); - fs.exists(filePath, function(exists) { - if(exists && fs.lstatSync(filePath).isFile()) { + fs.exists(filePath, function (exists) { + if (exists && fs.lstatSync(filePath).isFile()) { const ext = path.parse(filePath).ext; const mimeType = mime.lookup(ext); res.setHeader("Content-Type", `${mimeType}; charset=utf-8`); @@ -67,5 +48,3 @@ class ExtensionsServer { }); } } - -module.exports = ExtensionsServer; diff --git a/app/javascripts/main/fileUtils.js b/app/javascripts/main/fileUtils.js index 7ee60e94..a444bba8 100644 --- a/app/javascripts/main/fileUtils.js +++ b/app/javascripts/main/fileUtils.js @@ -1,16 +1,13 @@ -var {ipcMain, remote, dialog, app} = require('electron'); +var { app } = require('electron'); var fs = require('fs'); var path = require('path'); -var http = require('http'); -var https = require('https'); var request = require("request"); var appPath = app.getPath('userData'); -class FileUtils { - +export class FileUtils { readJSONFile(path, callback) { fs.readFile(path, 'utf8', function (err, data) { - if(err) { + if (err) { console.error("Unable to read JSON file", path); callback(null, err); return; @@ -62,19 +59,19 @@ class FileUtils { request(url) .on('error', function (err) { - console.log('File download error', url, err); + console.log('File download error', url, err); callback && callback() callback = null; }) - .on('response', function(response) { - if(response.statusCode !== 200) { + .on('response', function (response) { + if (response.statusCode !== 200) { console.log("File download not 200", url); callback && callback(response); callback = null; } }) .pipe(fs.createWriteStream(filePath)) - .on('close', function() { + .on('close', function () { console.log('File download success', url); callback && callback(null) callback = null; @@ -85,8 +82,8 @@ class FileUtils { var targetFile = target; //if target is a directory a new file with the same name will be created - if(fs.existsSync(target)) { - if(fs.lstatSync(target).isDirectory()) { + if (fs.existsSync(target)) { + if (fs.lstatSync(target).isDirectory()) { targetFile = path.join(target, path.basename(source)); } } @@ -100,7 +97,7 @@ class FileUtils { // Check if folder needs to be created or integrated var targetFolder = addBase ? path.join(target, path.basename(source)) : target; - if(!fs.existsSync(targetFolder)) { + if (!fs.existsSync(targetFolder)) { fs.mkdirSync(targetFolder); } @@ -109,7 +106,7 @@ class FileUtils { files = fs.readdirSync(source); files.forEach((file) => { var curSource = path.join(source, file); - if(fs.lstatSync(curSource).isDirectory()) { + if (fs.lstatSync(curSource).isDirectory()) { this.copyFolderRecursiveSync(curSource, targetFolder, true); } else { this.copyFileSync(curSource, targetFolder); @@ -117,7 +114,4 @@ class FileUtils { }); } } - } - -export default new FileUtils(); diff --git a/app/javascripts/main/index.js b/app/javascripts/main/index.js new file mode 100644 index 00000000..40ed750b --- /dev/null +++ b/app/javascripts/main/index.js @@ -0,0 +1,9 @@ +export { ArchiveManager } from './archiveManager'; +export { ExtensionsServer } from './extServer'; +export { FileUtils } from './fileUtils'; +export { MenuManager } from './menuManager'; +export { PackageManager } from './packageManager'; +export { SearchManager } from './searchManager'; +export { TrayManager } from './TrayManager'; +export { UpdateManager } from './updateManager'; +export { ZoomManager } from './zoomManager'; diff --git a/app/javascripts/main/menuManager.js b/app/javascripts/main/menuManager.js index 7a0ce319..d96d4211 100644 --- a/app/javascripts/main/menuManager.js +++ b/app/javascripts/main/menuManager.js @@ -1,27 +1,24 @@ -const shell = require('electron').shell; -const {app, Menu, dialog} = require('electron'); -const path = require('path') -const Store = require('./store.js'); +import { Store, StoreKeys } from './store'; +const { app, Menu, dialog, shell } = require('electron'); -class MenuManager { - - reload() { - this.loadMenu(this.window, this.archiveManager, this.updateManager, this.trayManager); - } - - loadMenu(window, archiveManager, updateManager, trayManager) { +export class MenuManager { + constructor(window, archiveManager, updateManager, trayManager) { this.window = window; this.archiveManager = archiveManager; this.updateManager = updateManager; this.trayManager = trayManager; + } - let updateData = updateManager.getMetadata(); - let useSystemMenuBar = Store.instance().get("useSystemMenuBar"); - let isMenuBarVisible = Store.instance().get("isMenuBarVisible"); - let minimizeToTray = trayManager.shouldMinimizeToTray(); - - window.setMenuBarVisibility(isMenuBarVisible); + reload() { + this.loadMenu(); + } + loadMenu() { + const updateData = this.updateManager.getMetadata(); + const useSystemMenuBar = Store.get(StoreKeys.UseSystemMenuBar); + const minimizeToTray = this.trayManager.shouldMinimizeToTray(); + let isMenuBarVisible = Store.get(StoreKeys.MenuBarVisible); + this.window.setMenuBarVisibility(isMenuBarVisible); const template = [ { label: 'Edit', @@ -52,7 +49,6 @@ class MenuManager { } ] }, - { label: 'View', submenu: [ @@ -89,8 +85,8 @@ class MenuManager { accelerator: 'Alt + m', click: () => { isMenuBarVisible = !isMenuBarVisible; - window.setMenuBarVisibility(isMenuBarVisible); - Store.instance().set("isMenuBarVisible", isMenuBarVisible); + this.window.setMenuBarVisibility(isMenuBarVisible); + Store.set(StoreKeys.MenuBarVisible, isMenuBarVisible); } }, { @@ -99,9 +95,12 @@ class MenuManager { type: 'checkbox', checked: !useSystemMenuBar, click: () => { - Store.instance().set("useSystemMenuBar", !useSystemMenuBar); + Store.set(StoreKeys.UseSystemMenuBar, !useSystemMenuBar); this.reload(); - dialog.showMessageBox({title: "Preference Changed", message: "Your menu bar preference has been saved. Please restart the application for the change to take effect."}); + dialog.showMessageBox({ + title: "Preference Changed", + message: "Your menu bar preference has been saved. Please restart the application for the change to take effect." + }); } } ] @@ -124,10 +123,10 @@ class MenuManager { type: 'checkbox', checked: minimizeToTray, click: () => { - Store.instance().set("minimizeToTray", !minimizeToTray); + Store.set(StoreKeys.MinimizeToTray, !minimizeToTray); this.reload(); - if(trayManager.shouldMinimizeToTray()) { - trayManager.createTrayIcon(); + if (this.trayManager.shouldMinimizeToTray()) { + this.trayManager.createTrayIcon(); } } } @@ -136,77 +135,92 @@ class MenuManager { { label: 'Backups', submenu: [ - {label: (archiveManager.isBackupsEnabled() ? 'Disable' : 'Enable') + ' Automatic Backups', click: () => { - archiveManager.toggleBackupsStatus(); - this.reload(); - }}, + { + label: ( + this.archiveManager.isBackupsEnabled() ? 'Disable' : 'Enable' + ) + ' Automatic Backups', + click: () => { + this.archiveManager.toggleBackupsStatus(); + this.reload(); + } + }, { type: 'separator' }, - {label: 'Change Backups Location', click() { - archiveManager.changeBackupsLocation(); - }}, - {label: 'Open Backups Location', click() { - shell.openItem(archiveManager.getBackupsLocation()); - }} + { + label: 'Change Backups Location', + click: () => { + this.archiveManager.changeBackupsLocation(); + } + }, + { + label: 'Open Backups Location', + click: () => { + shell.openItem(this.archiveManager.getBackupsLocation()); + } + } ] }, - this.buildUpdateMenu(updateData), - { role: 'help', submenu: [ { - label: 'GitHub', - click () { shell.openExternal('https://github.com/standardnotes') } + label: 'Email Support', + click: () => { shell.openExternal('mailto:help@standardnotes.org') } }, { - label: 'Slack', - click () { shell.openExternal('https://standardnotes.org/slack') } + label: 'Website', + click: () => { shell.openExternal('https://standardnotes.org') } }, { - label: 'Website', - click () { shell.openExternal('https://standardnotes.org') } + label: 'GitHub', + click: () => { shell.openExternal('https://github.com/standardnotes') } + }, + { + label: 'Slack', + click: () => { shell.openExternal('https://standardnotes.org/slack') } }, { - label: 'Support', - click () { shell.openExternal('mailto:hello@standardnotes.org') } + label: 'Twitter', + click: () => { shell.openExternal('https://twitter.com/StandardNotes') } }, { type: 'separator' }, { label: "Toggle Error Console", - click () { - window.webContents.toggleDevTools(); - } + click: () => { + this.window.webContents.toggleDevTools(); + } }, { label: 'Open Data Directory', - click () { - var userDataPath = app.getPath('userData'); + click: () => { + const userDataPath = app.getPath('userData'); shell.openItem(userDataPath); - } + } }, { label: 'Clear Cache and Reload', - click () { - window.webContents.session.clearCache(function(){ - window.reload(); + click: () => { + this.window.webContents.session.clearCache(() => { + this.window.reload(); }); - } + } }, { type: 'separator' }, { label: 'Version: ' + app.getVersion(), - click () { shell.openExternal('https://github.com/standardnotes/desktop/releases') } + click: () => { + shell.openExternal('https://github.com/standardnotes/desktop/releases'); + } } ] } - ] + ]; if (process.platform === 'darwin') { template.unshift({ @@ -241,8 +255,8 @@ class MenuManager { role: 'quit' } ] - }) - // Edit menu. + }); + /* Edit menu. */ template[1].submenu.push( { type: 'separator' @@ -258,8 +272,8 @@ class MenuManager { } ] } - ) - // Window menu. + ); + /* Window menu. */ template[3].submenu = [ { label: 'Close', @@ -282,7 +296,7 @@ class MenuManager { label: 'Bring All to Front', role: 'front' } - ] + ]; } this.menu = Menu.buildFromTemplate(template); @@ -290,86 +304,102 @@ class MenuManager { } popupMenu(position) { - if(this.menu) { + if (this.menu) { this.menu.popup(this.window, position.x, position.y); } } buildUpdateMenu(updateData) { - let updateNeeded = this.updateManager.updateNeeded(); - var label = updateData.checkingForUpdate ? "Checking for update..." : (updateNeeded ? "(1) Update Available" : 'Updates'); - var structure = { label: label }; - - var submenu = []; + const updateNeeded = this.updateManager.updateNeeded(); + const label = updateData.checkingForUpdate + ? "Checking for update..." + : (updateNeeded ? "(1) Update Available" : 'Updates'); + const structure = { label: label }; + const submenu = []; - if(this.updateManager.autoupdateDownloaded()) { + if (this.updateManager.autoupdateDownloaded()) { submenu.push({ - label: `Install Pending Update (${this.updateManager.autoupdateDownloadedVersion()})`, + label: `Install Pending Update + (${this.updateManager.autoupdateDownloadedVersion()}) + `, click: () => { this.updateManager.installAutoupdateNow(); } - }) + }); } submenu.push({ - label: this.updateManager.autoupdateEnabled() ? "Automatic Updates Enabled (Beta)" : "Automatic Updates Disabled", + label: this.updateManager.autoupdateEnabled() + ? "Automatic Updates Enabled" + : "Automatic Updates Disabled", click: () => { this.updateManager.toggleAutoupdateStatus(); } - }) + }); - submenu.push({type: 'separator'}); + submenu.push({ type: 'separator' }); - if(updateData.lastCheck && !updateData.checkinForUpdate) { + if (updateData.lastCheck && !updateData.checkinForUpdate) { submenu.push({ label: `Last checked ${updateData.lastCheck.toLocaleString()}`, - click() {} - }) + click: () => { } + }); } - if(!updateData.checkinForUpdate) { + if (!updateData.checkinForUpdate) { submenu.push({ label: `Check for Update`, - click: () => { this.updateManager.checkForUpdate({userTriggered: true}); } - }) + click: () => { + this.updateManager.checkForUpdate({ userTriggered: true }); + } + }); } - submenu.push({type: 'separator'}); + submenu.push({ type: 'separator' }); - submenu.push({label: `Your Version: ${updateData.currentVersion}`, click() { - - }}) + submenu.push({ + label: `Your Version: ${updateData.currentVersion}`, + click: () => {} + }); - let latestVersion = this.updateManager.latestVersion(); - submenu.push({label: `Latest Version: ${latestVersion ? latestVersion : 'Error Retrieving'}`, click: () => { - this.updateManager.openChangelog(); - }}) + const latestVersion = this.updateManager.latestVersion(); + submenu.push({ + label: `Latest Version: ${latestVersion || 'Error Retrieving'}`, + click: () => { + this.updateManager.openChangelog(); + } + }); - submenu.push({type: 'separator'}); + submenu.push({ type: 'separator' }); - submenu.push({label: `View ${latestVersion} Release Notes`, click: () => { - this.updateManager.openChangelog(); - }}) + submenu.push({ + label: `View ${latestVersion} Release Notes`, + click: () => { + this.updateManager.openChangelog(); + } + }); - if(updateData.latestDownloaded) { + if (updateData.latestDownloaded) { submenu.push({ label: "Open Download Location", click: () => { this.updateManager.openDownloadLocation(); } - }) - } else if(updateNeeded || updateData.downloadingUpdate) { + }); + } else if (updateNeeded || updateData.downloadingUpdate) { submenu.push({ - label: updateData.downloadingUpdate ? "Downloading update..." : "Manually Download Update", + label: updateData.downloadingUpdate + ? "Downloading update..." + : "Manually Download Update", click: () => { - updateData.downloadingUpdate ? this.updateManager.openDownloadLocation() : this.updateManager.downloadUpdateFile(); + updateData.downloadingUpdate + ? this.updateManager.openDownloadLocation() + : this.updateManager.downloadUpdateFile(); } - }) + }); } structure.submenu = submenu; return structure; } } - -export default new MenuManager(); diff --git a/app/javascripts/main/packageManager.js b/app/javascripts/main/packageManager.js index 650e1459..c0d0c6b3 100644 --- a/app/javascripts/main/packageManager.js +++ b/app/javascripts/main/packageManager.js @@ -1,21 +1,20 @@ -const {ipcMain, remote, dialog, app} = require('electron'); +import { FileUtils } from "./fileUtils"; +const { ipcMain, app } = require('electron'); const fs = require('fs'); const path = require('path'); -const http = require('http'); -const https = require('https'); const request = require("request"); const appPath = app.getPath('userData'); const AdmZip = require('adm-zip'); const compareVersions = require('compare-versions'); - -import fileUtils from "./fileUtils"; +const fileUtils = new FileUtils(); const ExtensionsFolderName = "Extensions"; const MappingFileLocation = appPath + `/${ExtensionsFolderName}/mapping.json`; -class PackageManager { +export class PackageManager { - constructor() { + constructor(window) { + this.window = window; ipcMain.on('install-component', (event, data) => { this.installComponent(data.componentData); }); @@ -25,12 +24,8 @@ class PackageManager { }); } - setWindow(window) { - this.window = window; - } - pathsForComponent(component) { - let relativePath = `${ExtensionsFolderName}/` + component.content.package_info.identifier; + const relativePath = `${ExtensionsFolderName}/` + component.content.package_info.identifier; return { downloadPath: appPath + `/${ExtensionsFolderName}/downloads/` + component.content.name + ".zip", relativePath: relativePath, @@ -39,36 +34,36 @@ class PackageManager { } installComponent(component) { - let downloadUrl = component.content.package_info.download_url; - if(!downloadUrl) { + const downloadUrl = component.content.package_info.download_url; + if (!downloadUrl) { return; } console.log("Installing component", component.content.name, downloadUrl); - let callback = (installedComponent, error) => { - this.window.webContents.send("install-component-complete", {component: installedComponent, error: error}); - } + const callback = (installedComponent, error) => { + this.window.webContents.send("install-component-complete", { component: installedComponent, error: error }); + }; - let paths = this.pathsForComponent(component); + const paths = this.pathsForComponent(component); fileUtils.downloadFile(downloadUrl, paths.downloadPath, (error) => { - if(!error) { + if (!error) { // Delete any existing content, especially in the case of performing an update fileUtils.deleteAppRelativeDirectory(paths.relativePath); // Extract contents this.unzipFile(paths.downloadPath, paths.absolutePath, (err) => { - if(!err) { + if (!err) { this.unnestPackageContents(paths.absolutePath, () => { // Find out main file fileUtils.readJSONFile(paths.absolutePath + "/package.json", (response, error) => { var main; - if(response) { - if(response.sn) { main = response["sn"]["main"]; } - if(response.version) { component.content.package_info.version = response.version; } + if (response) { + if (response.sn) { main = response["sn"]["main"]; } + if (response.version) { component.content.package_info.version = response.version; } } - if(!main) { main = "index.html"; } + if (!main) { main = "index.html"; } component.content.local_url = "sn://" + paths.relativePath + "/" + main; callback(component); @@ -80,12 +75,12 @@ class PackageManager { } else { // Unzip error console.log("Unzip error for", component.content.name); - callback(component, {tag: "error-unzipping"}) + callback(component, { tag: "error-unzipping" }) } }); } else { // Download error - callback(component, {tag: "error-downloading"}) + callback(component, { tag: "error-downloading" }) } }); } @@ -96,16 +91,16 @@ class PackageManager { */ updateMappingFile(componentId, componentPath) { fileUtils.readJSONFile(MappingFileLocation, (response, error) => { - if(!response) response = {}; + if (!response) response = {}; var obj = response[componentId] || {}; obj["location"] = componentPath; response[componentId] = obj; fs.writeFile(MappingFileLocation, JSON.stringify(response, null, 2), 'utf8', (err) => { - if(err) console.log("Mapping file save error:", err); + if (err) console.log("Mapping file save error:", err); }); - }) + }); } syncComponents(components) { @@ -114,48 +109,52 @@ class PackageManager { console.log(`Syncing components: ${components.length}`); - for(let component of components) { - if(component.deleted) { + for (const component of components) { + if (component.deleted) { // Uninstall this.uninstallComponent(component); continue; } - if(!component.content.package_info) { + if (!component.content.package_info) { console.log("Package info is null, continuing"); continue; } - let paths = this.pathsForComponent(component); + const paths = this.pathsForComponent(component); fs.stat(paths.absolutePath, (err, stats) => { var doesntExist = err && err.code === 'ENOENT'; - if(doesntExist || !component.content.local_url) { + if (doesntExist || !component.content.local_url) { // Doesn't exist, install it this.installComponent(component); - } else if(!component.content.autoupdateDisabled) { + } else if (!component.content.autoupdateDisabled) { // Check for updates this.checkForUpdate(component); } else { // Already exists or update update disabled - console.log("Not installing component", component.content.name, "Already exists?", !doesntExist); + console.log("Not installing component", component.content.name, "Already exists?", !doesntExist); } - }) + }); } } async checkForUpdate(component) { var latestURL = component.content.package_info.latest_url; - if(!latestURL) { + if (!latestURL) { console.log("No latest url, skipping update", component.content.name); return; } request.get(latestURL, async (error, response, body) => { - if(response.statusCode == 200) { - var payload = JSON.parse(body); - let installedVersion = await this.getInstalledVersionForComponent(component); - console.log("Checking for update for:", component.content.name, "Latest Version:", payload.version, "Installed Version", installedVersion); - if(payload && payload.version && compareVersions(payload.version, installedVersion) == 1) { + if (!error && response.statusCode == 200) { + const payload = JSON.parse(body); + const installedVersion = await this.getInstalledVersionForComponent(component); + console.log("Checking for update for:", component.content.name, + "Latest Version:", payload.version, "Installed Version", installedVersion); + if ( + payload && payload.version + && compareVersions(payload.version, installedVersion) === 1 + ) { // Latest version is greater than installed version console.log("Downloading new version", payload.download_url); component.content.package_info.download_url = payload.download_url; @@ -169,46 +168,42 @@ class PackageManager { async getInstalledVersionForComponent(component) { // We check package.json version rather than component.content.package_info.version // because we want device specific versions rather than a globally synced value - let paths = this.pathsForComponent(component); - let packagePath = path.join(paths.absolutePath, "package.json"); + const paths = this.pathsForComponent(component); + const packagePath = path.join(paths.absolutePath, "package.json"); return new Promise((resolve, reject) => { - fileUtils.readJSONFile(packagePath, (response, error) => { - if(!response) { + fileUtils.readJSONFile(packagePath, (response, error) => { + if (!response) { resolve(null); } else { resolve(response['version']); } - }) - }) + }); + }); } uninstallComponent(component) { console.log("Uninstalling component", component.uuid); fileUtils.readJSONFile(MappingFileLocation, (response, error) => { - if(!response) { + if (!response) { // No mapping.json means nothing is installed return; } // Get installation location - var mapping = response[component.uuid]; - if(!mapping || !mapping.location) { + const mapping = response[component.uuid]; + if (!mapping || !mapping.location) { return; } - let location = mapping["location"]; - + const location = mapping["location"]; fileUtils.deleteAppRelativeDirectory(location); - delete response[component.uuid]; - fs.writeFile(MappingFileLocation, JSON.stringify(response, null, 2), 'utf8', (err) => { - if(err) console.log("Uninstall, mapping file save error:", err); + if (err) console.log("Uninstall, mapping file save error:", err); }); - }) + }); } - /* File/Network Operations */ @@ -216,10 +211,10 @@ class PackageManager { unzipFile(filePath, dest, callback) { console.log("Unzipping file at", filePath, "to", dest); fs.readFile(filePath, 'utf8', function (err, data) { - if(err) { - console.log("Unzip File Error", err); - callback(err); - return; + if (err) { + console.log("Unzip File Error", err); + callback(err); + return; } var zip = new AdmZip(filePath); @@ -238,15 +233,15 @@ class PackageManager { unnestPackageContents(directory, callback) { // console.log("unnestPackageContents", directory); fs.readdir(directory, (err, files) => { - if(err) { + if (err) { callback(); return; } - if(files.length == 1) { + if (files.length === 1) { var file = files[0]; var location = path.join(directory, file); - if(fs.statSync(location).isDirectory()) { + if (fs.statSync(location).isDirectory()) { // Unnest fileUtils.copyFolderRecursiveSync(location, directory, false); callback(); @@ -257,7 +252,4 @@ class PackageManager { callback(); }); } - } - -export default new PackageManager(); diff --git a/app/javascripts/main/searchManager.js b/app/javascripts/main/searchManager.js index fdb7faf8..0e44523a 100644 --- a/app/javascripts/main/searchManager.js +++ b/app/javascripts/main/searchManager.js @@ -1,23 +1,20 @@ -var {ipcMain, remote, dialog, app} = require('electron'); +const { ipcMain } = require('electron'); -class SearchManager { +export class SearchManager { - constructor() { + constructor(window) { + this.window = window; ipcMain.on('search-text', (event, data) => { - let text = data.text; + const text = data.text; this.window.webContents.stopFindInPage('clearSelection'); - if(text && text.length > 0) { + if (text && text.length > 0) { // This option arrangement is required to avoid an issue where clicking on a // different note causes scroll to jump. - this.window.webContents.findInPage(text, {forward: true, findNext: false}); + this.window.webContents.findInPage( + text, + { forward: true, findNext: false } + ); } }); } - - setWindow(window) { - this.window = window; - } - } - -export default new SearchManager(); diff --git a/app/javascripts/main/store.js b/app/javascripts/main/store.js index 4c35aaf8..af0567c2 100644 --- a/app/javascripts/main/store.js +++ b/app/javascripts/main/store.js @@ -2,13 +2,22 @@ const electron = require('electron'); const path = require('path'); const fs = require('fs'); -let instance = null; +export const StoreKeys = { + ExtServerHost: 'extServerHost', + UseSystemMenuBar: 'useSystemMenuBar', + MenuBarVisible: 'isMenuBarVisible', + BackupsLocation: 'backupsLocation', + BackupsDisabled: 'backupsDisabled', + MinimizeToTray: 'minimizeToTray', + ZoomFactor: 'zoomFactor' +}; -class Store { +export class Store { + static instance = null; - static instance() { - if (instance == null) { - instance = new Store({ + static getInstance() { + if (!this.instance) { + this.instance = new Store({ configName: 'user-preferences', defaults: { useSystemMenuBar: false, @@ -17,25 +26,32 @@ class Store { }); } - return instance; + return this.instance; + } + + static get(key) { + return this.getInstance().get(key); + } + + static set(key, val) { + return this.getInstance().set(key, val); } constructor(opts) { - // Renderer process has to get `app` module via `remote`, whereas the main process can get it directly - // app.getPath('userData') will return a string of the user's app data directory path. + /** + * Renderer process has to get `app` module via `remote`, whereas the main process + * can get it directly app.getPath('userData') will return a string of the user's + * app data directory path. + */ const userDataPath = (electron.app || electron.remote.app).getPath('userData'); - // We'll use the `configName` property to set the file name and path.join to bring it all together as a string this.path = path.join(userDataPath, opts.configName + '.json'); - this.data = parseDataFile(this.path, opts.defaults); } - // This will just return the property on the `data` object get(key) { return this.data[key]; } - // ...and this will set it set(key, val) { this.data[key] = val; fs.writeFileSync(this.path, JSON.stringify(this.data)); @@ -47,10 +63,6 @@ function parseDataFile(filePath, defaults) { const userData = JSON.parse(fs.readFileSync(filePath)); return Object.assign(defaults, userData); } catch(error) { - // if there was some kind of error, return the passed in defaults instead. return defaults; } } - -// expose the class -module.exports = Store; diff --git a/app/javascripts/main/trayManager.js b/app/javascripts/main/trayManager.js index 84d2a7aa..5621a8ac 100644 --- a/app/javascripts/main/trayManager.js +++ b/app/javascripts/main/trayManager.js @@ -1,19 +1,18 @@ +import { Store, StoreKeys } from './store'; const path = require('path'); -const {Tray, Menu, app} = require('electron'); -const Store = require('./store.js'); - +const { Tray, Menu, app } = require('electron'); const icon = path.join(__dirname, `../../icon/Icon-256x256.png`); -class TrayManager { - setWindow(window) { +export class TrayManager { + constructor(window) { this.window = window; } - shouldMinimizeToTray () { - return Store.instance().get("minimizeToTray"); + shouldMinimizeToTray() { + return Store.get(StoreKeys.MinimizeToTray); } - createTrayIcon () { + createTrayIcon() { const tray = new Tray(icon); tray.toggleWindowVisibility = (show) => { @@ -81,5 +80,3 @@ class TrayManager { }); } } - -export default new TrayManager(); diff --git a/app/javascripts/main/updateManager.js b/app/javascripts/main/updateManager.js index 7eedeac1..bc5c3e94 100644 --- a/app/javascripts/main/updateManager.js +++ b/app/javascripts/main/updateManager.js @@ -1,46 +1,44 @@ -var {ipcMain, remote, dialog, app} = require('electron'); +import { FileUtils } from "./fileUtils"; +const { dialog, app } = require('electron'); const shell = require('electron').shell; -var fs = require('fs'); -var path = require('path'); -var http = require('http'); -var https = require('https'); -var os = require('os'); -var request = require("request"); -var appPath = app.getPath('userData'); -var compareVersions = require('compare-versions'); -const {autoUpdater} = require("electron-updater"); +const os = require('os'); +const request = require("request"); +const appPath = app.getPath('userData'); +const compareVersions = require('compare-versions'); +const { autoUpdater } = require("electron-updater"); const log = require('electron-log'); const isDev = require('electron-is-dev'); -import fileUtils from "./fileUtils"; +const fileUtils = new FileUtils(); -let UpdateFoldersName = "Updates"; -let DefaultUpdateEndpoint = process.env.UPDATE_ENDPOINT || "https://standardnotes.org/desktop/latest.json"; +const UpdateFoldersName = "Updates"; +const DefaultUpdateEndpoint = process.env.UPDATE_ENDPOINT || + 'https://standardnotes.org/desktop/latest.json'; -class UpdateManager { +export class UpdateManager { - constructor() { + constructor(window) { + this.window = window; this.metadata = {}; this.getUpdateInfoFile((data) => { - if(!data) { - data = {endpoint: DefaultUpdateEndpoint, autoupdateEnabled: true}; + if (!data) { + data = { + endpoint: DefaultUpdateEndpoint, + autoupdateEnabled: true + }; } this.metadata = data; this.checkForUpdate(); - }) + }); - autoUpdater.logger = log + autoUpdater.logger = log; autoUpdater.on("update-downloaded", (info) => { this.window.webContents.send("update-available", null); this.__autoupdateDownloaded = true; this.autoupdateInfo = info; this.triggerMenuReload(); - }) - } - - setWindow(window) { - this.window = window; + }); } autoupdateDownloaded() { @@ -64,13 +62,13 @@ class UpdateManager { // index.js prevents close event on some platforms this.window.removeAllListeners("close"); this.window.close(); - autoUpdater.quitAndInstall(false) - }) + autoUpdater.quitAndInstall(false); + }); } else { - autoUpdater.enabled = true + autoUpdater.enabled = true; } - }) + }); } getMetadata() { @@ -78,7 +76,8 @@ class UpdateManager { } updateNeeded() { - return this.metadata.latest && compareVersions(this.metadata.latest.version, app.getVersion()) == 1; + return this.metadata.latest && + compareVersions(this.metadata.latest.version, app.getVersion()) === 1; } autoupdateEnabled() { @@ -90,8 +89,13 @@ class UpdateManager { this.saveInfoFile(); this.triggerMenuReload(); - if(this.metadata.autoupdateEnabled) { - dialog.showMessageBox({title: "Automatic Updates Enabled.", message: "Automatic updates have been enabled. Please note that this functionality is currently in beta, and that you are advised to periodically check in and ensure you are running the latest version."}); + if (this.metadata.autoupdateEnabled) { + dialog.showMessageBox({ + title: "Automatic Updates Enabled.", + message: `Automatic updates have been enabled. Please note that this functionality + is currently in beta, and that you are advised to periodically check in and + ensure you are running the latest version.` + }); } } @@ -100,7 +104,7 @@ class UpdateManager { } __checkAutoupdate() { - if(isDev || !this.metadata.autoupdateEnabled) { return; } + if (isDev || !this.metadata.autoupdateEnabled) { return; } try { autoUpdater.checkForUpdates(); } catch (e) { @@ -113,18 +117,17 @@ class UpdateManager { console.log("Checking for updates..."); this.__checkAutoupdate(); - this.metadata.checkingForUpdate = true; this.triggerMenuReload(); - - let currentVersion = app.getVersion(); + const currentVersion = app.getVersion(); this.__getLatest((latest, error) => { - if(!latest) { latest = {}; } - if(latest.version) { + if (!latest) { latest = {}; } + if (latest.version) { this.metadata.latest = latest; } - console.log(`Finished checking for updates. Latest version: ${latest.version} Current version: ${currentVersion}`); + console.log(`Finished checking for updates. Latest version: + ${latest.version} Current version: ${currentVersion}`); this.metadata.currentVersion = currentVersion; this.metadata.checkingForUpdate = false; @@ -132,27 +135,30 @@ class UpdateManager { // Update info file with last check this.metadata.lastCheck = new Date(); - if(options.userTriggered) { + if (options.userTriggered) { var message = this.updateNeeded() - ? `A new update is available (version ${this.metadata.latest.version}). You can attempt upgrading through auto-update (beta), or manually download and install this update.` - : `Your version (${this.metadata.currentVersion}) is the latest available version.`; + ? `A new update is available (version ${this.metadata.latest.version}). + You can attempt upgrading through auto-update, or manually download and install this update.` + : `Your version (${this.metadata.currentVersion}) is the latest available version.`; - if(error) { + if (error) { message = "An issue occurred while checking for updates. Please try again."; } - dialog.showMessageBox({title: "Finished checking for updates.", message: message}); + dialog.showMessageBox({ + title: "Finished checking for updates.", + message: message + }); } this.triggerMenuReload(); - this.saveInfoFile(); - }) + }); } downloadUpdateFile() { - var platformKey = this.getPlatformKey(); - if(!platformKey) { + const platformKey = this.getPlatformKey(); + if (!platformKey) { // Open GitHub releases this.openChangelog(); return; @@ -161,38 +167,39 @@ class UpdateManager { this.metadata.downloadingUpdate = true; this.triggerMenuReload(); - var url = this.metadata.latest.downloads[platformKey]; - var filename = url.split('/').pop() - let path = appPath + "/" + UpdateFoldersName + "/" + filename; + const url = this.metadata.latest.downloads[platformKey]; + const filename = url.split('/').pop() + const path = appPath + "/" + UpdateFoldersName + "/" + filename; console.log("Downloading update file", url); fileUtils.downloadFile(url, path, (error) => { this.metadata.downloadingUpdate = false; - if(!error) { + if (!error) { this.metadata.latestDownloaded = true; this.saveInfoFile(); this.openDownloadLocation(); } else { - dialog.showMessageBox({title: "Error Downloading", message: "An error occurred while trying to download your update file. Please try again."}); + dialog.showMessageBox({ + title: "Error Downloading", + message: "An error occurred while trying to download your update file. Please try again." + }); } this.triggerMenuReload(); - }) + }); } getPlatformKey() { - var platformKey; - // possible remote keys for platforms are: mac, windows, appimage_x86, appimage_x64 - - // 'darwin', 'linux', 'openbsd', 'win32' - var nativePlatform = os.platform(); - if(nativePlatform == "darwin") { + /* mac, windows, appimage_x86, appimage_x64 */ + let platformKey; + /* 'darwin', 'linux', 'openbsd', 'win32' */ + const nativePlatform = os.platform(); + if (nativePlatform === "darwin") { platformKey = "mac"; - } else if(nativePlatform.includes("win")) { + } else if (nativePlatform.includes("win")) { platformKey = "windows"; } else { - // Linux - // possible values are: 'arm', 'arm64', 'ia32', 'x32', and 'x64'. - var arch = os.arch(); - if(arch == "x64") { + /* Linux; possible values are: 'arm', 'arm64', 'ia32', 'x32', and 'x64'. */ + const arch = os.arch(); + if (arch === "x64") { platformKey = "appimage_64"; } else { platformKey = "appimage_32"; @@ -214,35 +221,31 @@ class UpdateManager { } metaFilePath() { - let path = appPath + "/" + UpdateFoldersName + "/" + "settings.json"; + const path = appPath + "/" + UpdateFoldersName + "/" + "settings.json"; return path; } saveInfoFile() { - let path = this.metaFilePath(); - fileUtils.writeJSONFile(this.metadata, path, (writeError) => { - - }) + const path = this.metaFilePath(); + fileUtils.writeJSONFile(this.metadata, path, (writeError) => { }); } getUpdateInfoFile(callback) { // Check for update info file - let path = this.metaFilePath(); + const path = this.metaFilePath(); fileUtils.readJSONFile(path, (data, readError) => { callback(data); - }) + }); } __getLatest(callback) { - let url = this.metadata.endpoint; + const url = this.metadata.endpoint; request.get(url, (error, response, body) => { - if(response && response.statusCode == 200) { + if (response && response.statusCode === 200) { callback(JSON.parse(body)); } else { callback(null, error || {}); } - }) + }); } } - -export default new UpdateManager(); diff --git a/app/javascripts/main/zoomManager.js b/app/javascripts/main/zoomManager.js index 5bfc5172..77fbde91 100644 --- a/app/javascripts/main/zoomManager.js +++ b/app/javascripts/main/zoomManager.js @@ -1,29 +1,23 @@ -const store = require('./store') +import { Store, StoreKeys } from './store'; -class ZoomManager { - - setWindow(window) { +export class ZoomManager { + constructor(window) { this.window = window; this.bind(); } bind() { - // We can't rely on ready-to-show as it doesn't fire consistently - // See: https://github.com/electron/electron/issues/7779 this.window.webContents.on('dom-ready', () => { - const zoomFactor = store.instance().get('zoomFactor'); + const zoomFactor = Store.get(StoreKeys.ZoomFactor); if (zoomFactor) { this.window.webContents.setZoomFactor(zoomFactor); } - }) + }); this.window.on('close', () => { - // Persist the zoom level this.window.webContents.getZoomFactor((zoomFactor) => { - store.instance().set('zoomFactor', zoomFactor); + Store.set(StoreKeys.ZoomFactor, zoomFactor); }); - }) + }); } } - -export default new ZoomManager(); diff --git a/app/javascripts/renderer/preload.js b/app/javascripts/renderer/preload.js index edfb2997..95140599 100644 --- a/app/javascripts/renderer/preload.js +++ b/app/javascripts/renderer/preload.js @@ -1,13 +1,18 @@ -const { webFrame, ipcRenderer, remote } = require('electron') +import { + Transmitter, + FrameMessageBus, + Validation +} from 'sn-electron-valence/Transmitter'; +import { + Store, + StoreKeys +} from '../main/store'; +const { webFrame, ipcRenderer, remote } = require('electron'); const osLocale = require('os-locale'); -const os = require('os'); - -const Store = require('../main/store.js'); -const ExtensionsServer = require('../main/extServer.js') +const path = require('path'); const buildEditorContextMenu = remote.require('electron-editor-context-menu'); -const rendererPath = 'file://' + __dirname + '/renderer.js'; +const rendererPath = path.join('file://', __dirname, '/renderer.js'); -import { Transmitter, FrameMessageBus, Validation } from 'sn-electron-valence/Transmitter'; const { PropertyType } = Validation; const messageBus = new FrameMessageBus(); const transmitter = new Transmitter(messageBus, @@ -49,15 +54,15 @@ function loadTransmitter() { spellcheck = loadSpellcheck(); } catch (e) { console.error("Error loading spellcheck", e); - } + } transmitter.expose({ spellcheck: spellcheck, - extServerHost: ExtensionsServer.instance().getHost(), + extServerHost: Store.get(StoreKeys.ExtServerHost), rendererPath: rendererPath, isMacOS: process.platform === "darwin", appVersion: remote.app.getVersion(), - useSystemMenuBar: Store.instance().get("useSystemMenuBar"), + useSystemMenuBar: Store.get(StoreKeys.UseSystemMenuBar), // All functions must be async, as electron-valence expects to run .then() on them. sendIpcMessage: async (message, data) => { @@ -76,16 +81,18 @@ function loadTransmitter() { remote.getCurrentWindow().unmaximize(); }, isWindowMaximized: async () => { - return remote.getCurrentWindow().isMaximized() + return remote.getCurrentWindow().isMaximized(); }, }); } function listenForIpcEvents() { - const sendMessage = (message, payload = {}) => { - window.postMessage(JSON.stringify({message, data: payload}), rendererPath); - } + window.postMessage( + JSON.stringify({message, data: payload}), + rendererPath + ); + }; ipcRenderer.on('update-available', function (event, data) { sendMessage("update-available", data); @@ -128,7 +135,7 @@ function loadSpellcheck() { ]; // We load locale this way and not via app.getLocale() because this call returns - // 'es_ES' and not just 'es.' And hunspell requires the fully-qualified locale. + // 'es_ES' and not just 'es.' And hunspell requires the fully-qualified locale. const locale = osLocale.sync().replace('-', '_'); // The LANG environment variable is how node spellchecker finds its default language: @@ -140,12 +147,13 @@ function loadSpellcheck() { function debounce(func, wait, immediate) { var timeout; return function() { - var context = this, args = arguments; - var later = function() { + const context = this; + const args = arguments; + const later = function() { timeout = null; if (!immediate) func.apply(context, args); }; - var callNow = immediate && !timeout; + const callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); @@ -158,10 +166,10 @@ function loadSpellcheck() { callback(misspelled); }, 500), isMisspelled: function(text) { - var misspelled = spellchecker.isMisspelled(text); + const misspelled = spellchecker.isMisspelled(text); // The idea is to make this as fast as possible. For the many, many calls which - // don't result in the red squiggly, we minimize the number of checks. + // don't result in the red squiggly, we minimize the number of checks. if (!misspelled) { return false; } @@ -183,9 +191,9 @@ function loadSpellcheck() { return { showContextMenuForText: async (selectedText) => { - var isMisspelled = selectedText && simpleChecker.isMisspelled(selectedText); - var spellingSuggestions = isMisspelled && simpleChecker.getSuggestions(selectedText).slice(0, 5); - var menu = buildEditorContextMenu({ + const isMisspelled = selectedText && simpleChecker.isMisspelled(selectedText); + const spellingSuggestions = isMisspelled && simpleChecker.getSuggestions(selectedText).slice(0, 5); + const menu = buildEditorContextMenu({ isMisspelled: isMisspelled, spellingSuggestions: spellingSuggestions, }); diff --git a/app/javascripts/renderer/renderer.js b/app/javascripts/renderer/renderer.js index 315eed7b..ed23a673 100644 --- a/app/javascripts/renderer/renderer.js +++ b/app/javascripts/renderer/renderer.js @@ -11,9 +11,10 @@ const angularReady = new Promise((resolve, reject) => { angular.element(document).ready(function () { resolve(); }); -}) +}); -let bridge, desktopManager; +let bridge; +let desktopManager; Promise.all([ angularReady, @@ -27,7 +28,7 @@ Promise.all([ configureWindow(); configureSpellcheck(); loadZipLibrary(); -}) +}); async function configureWindow() { const isMacOS = await bridge.isMacOS; @@ -36,14 +37,17 @@ async function configureWindow() { window.electronAppVersion = await bridge.appVersion; // disable drag-n-drop of file in the app - document.addEventListener('dragover', event => event.preventDefault()) - document.addEventListener('drop', event => event.preventDefault()) + document.addEventListener('dragover', event => event.preventDefault()); + document.addEventListener('drop', event => event.preventDefault()); /* Title bar events */ document.getElementById("menu-btn").addEventListener("click", (e) => { - bridge.sendIpcMessage("display-app-menu", { x: e.x, y: e.y }) + bridge.sendIpcMessage( + "display-app-menu", + { x: e.x, y: e.y } + ); }); document.getElementById("min-btn").addEventListener("click", (e) => { @@ -66,15 +70,26 @@ async function configureWindow() { // For Mac inset window const sheet = window.document.styleSheets[0]; if(isMacOS) { - sheet.insertRule('#tags-column { padding-top: 25px !important; }', sheet.cssRules.length); + sheet.insertRule( + '#tags-column { padding-top: 25px !important; }', + sheet.cssRules.length + ); } if(isMacOS || useSystemMenuBar) { // !important is important here because #desktop-title-bar has display: flex. - sheet.insertRule('#desktop-title-bar { display: none !important; }', sheet.cssRules.length); + sheet.insertRule( + '#desktop-title-bar { display: none !important; }', + sheet.cssRules.length + ); } else { - // Use custom title bar. Take the sn-titlebar-height off of the app content height so its not overflowing - sheet.insertRule('.main-ui-view { height: calc(100vh - var(--sn-desktop-titlebar-height)) !important; min-height: calc(100vh - var(--sn-desktop-titlebar-height)) !important; }', sheet.cssRules.length); + /* Use custom title bar. Take the sn-titlebar-height off of + the app content height so its not overflowing */ + sheet.insertRule( + `.main-ui-view { height: calc(100vh - var(--sn-desktop-titlebar-height)) !important; + min-height: calc(100vh - var(--sn-desktop-titlebar-height)) !important; }`, + sheet.cssRules.length + ); } } @@ -82,10 +97,10 @@ async function configureDesktopManager() { const extServerHost = await bridge.extServerHost; desktopManager.desktop_setExtServerHost(extServerHost); - /* Handled by PackageManager */ desktopManager.desktop_setComponentInstallationSyncHandler(async (componentsData) => { + /* Handled by PackageManager */ bridge.sendIpcMessage("sync-components", {componentsData}); - }) + }); desktopManager.desktop_setInstallComponentHandler((componentData) => { bridge.sendIpcMessage("install-component", componentData); @@ -95,10 +110,10 @@ async function configureDesktopManager() { bridge.sendIpcMessage("search-text", {text}); }); - /* Handled by ArchiveManager */ desktopManager.desktop_setInitialDataLoadHandler(() => { + /* Handled by ArchiveManager */ bridge.sendIpcMessage("initial-data-loaded", {}); - }) + }); desktopManager.desktop_setMajorDataChangeHandler(() => { bridge.sendIpcMessage("major-data-change", {}); @@ -120,8 +135,8 @@ async function registerIpcMessageListener() { return; } - let message = payload.message; - let data = payload.data; + const message = payload.message; + const data = payload.data; if(message === "window-blurred") { desktopManager.desktop_windowLostFocus(); @@ -156,7 +171,7 @@ function loadZipLibrary() { headTag.appendChild(scriptTag); scriptTag.onload = function() { zip.workerScriptsPath = "./vendor/zip/"; - } + }; } async function configureSpellcheck() { @@ -169,9 +184,7 @@ async function configureSpellcheck() { if (!e.target.closest('textarea, input, [contenteditable="true"]')) { return; } - - let selectedText = window.getSelection().toString(); - + const selectedText = window.getSelection().toString(); // The 'contextmenu' event is emitted after 'selectionchange' has fired but possibly before the // visible selection has changed. Try to wait to show the menu until after that, otherwise the // visible selection will update after the menu dismisses and look weird. @@ -179,41 +192,4 @@ async function configureSpellcheck() { spellcheck.showContextMenuForText(selectedText); }, 30); }); - - // New electron versions (v5+) treat different file:// paths as different origins. Thus, - // our main frame can't inject anything into editor frames, so the below will not work. - /* - deprecated_configureSpellcheckForExternalEditors() { - function editorExtensionContextEvent(e) { - let selectedText = e.view.getSelection().toString(); - let menu = getContextMenuForText(selectedText); - - // The 'contextmenu' event is emitted after 'selectionchange' has fired but possibly before the - // visible selection has changed. Try to wait to show the menu until after that, otherwise the - // visible selection will update after the menu dismisses and look weird. - setTimeout(function() { - menu.popup({window: remote.getCurrentWindow()}); - }, 30); - } - - function addContextMenuTo(uuid) { - let componentFrame = document.querySelector('[data-component-id="' + uuid + '"]'); - if(componentFrame) { - // add content menu event - componentFrame.contentWindow.addEventListener("contextmenu", editorExtensionContextEvent); - } - } - - // register activation observer to be notified when a component is registered - desktopManager.desktop_registerComponentActivationObserver(async (component) => { - try { - // Reload spellcheck integration after iframe is loaded (https://github.com/electron/electron/issues/13514#issuecomment-445396551) - await spellcheck.reload(); - addContextMenuTo(component.uuid); - } catch (e) { - console.error(e); - } - }); - } - */ } diff --git a/app/package-lock.json b/app/package-lock.json index 0c7d2d1d..43bc8d39 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1022,8 +1022,8 @@ } }, "standard-notes-web": { - "version": "github:standardnotes/web#badadba8f8f215fb86242679c4076302a13f246d", - "from": "github:standardnotes/web#badadba8f8f215fb86242679c4076302a13f246d", + "version": "github:standardnotes/web#3c8c43ac7e8188a58e7da53311ccf6e023cf6f4a", + "from": "github:standardnotes/web#3c8c43ac7e8188a58e7da53311ccf6e023cf6f4a", "requires": { "lodash": "^4.17.15" } diff --git a/app/package.json b/app/package.json index 3db00ee8..5220d1ff 100644 --- a/app/package.json +++ b/app/package.json @@ -19,6 +19,6 @@ "semver": "^5.5.0", "sn-electron-valence": "0.0.4", "spellchecker": "github:mobitar/node-spellchecker", - "standard-notes-web": "github:standardnotes/web#badadba8f8f215fb86242679c4076302a13f246d" + "standard-notes-web": "github:standardnotes/web#3c8c43ac7e8188a58e7da53311ccf6e023cf6f4a" } } diff --git a/babel.config.js b/babel.config.js index 0d4d1b3e..4dc6e2a4 100644 --- a/babel.config.js +++ b/babel.config.js @@ -15,7 +15,8 @@ module.exports = function (api) { "generators": false, "async": false }], - "@babel/plugin-transform-async-to-generator" + "@babel/plugin-transform-async-to-generator", + "@babel/plugin-proposal-class-properties" ]; const ignore = [ diff --git a/package-lock.json b/package-lock.json index ec8e19e1..30d31e77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,6 +135,179 @@ "@babel/types": "^7.7.4" } }, + "@babel/helper-create-class-features-plugin": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz", + "integrity": "sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", + "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "dev": true, + "requires": { + "@babel/highlight": "^7.8.3" + } + }, + "@babel/generator": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz", + "integrity": "sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + } + }, + "@babel/helper-function-name": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", + "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.8.3", + "@babel/template": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", + "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", + "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", + "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + }, + "@babel/helper-replace-supers": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz", + "integrity": "sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/traverse": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", + "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "dev": true, + "requires": { + "@babel/types": "^7.8.3" + } + }, + "@babel/highlight": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz", + "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz", + "integrity": "sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==", + "dev": true + }, + "@babel/template": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz", + "integrity": "sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/parser": "^7.8.3", + "@babel/types": "^7.8.3" + } + }, + "@babel/traverse": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz", + "integrity": "sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@babel/generator": "^7.8.4", + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3", + "@babel/parser": "^7.8.4", + "@babel/types": "^7.8.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz", + "integrity": "sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "@babel/helper-create-regexp-features-plugin": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.4.tgz", @@ -346,6 +519,24 @@ "@babel/plugin-syntax-async-generators": "^7.7.4" } }, + "@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", + "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", + "dev": true + } + } + }, "@babel/plugin-proposal-dynamic-import": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz", @@ -917,6 +1108,18 @@ "integrity": "sha512-An+MXSV8CGXz/BO9C1KKsoJ/8WDrvlNUaRMsm2h+IHZuSyQkM8U5bJJkb8ItLKA73VePG/nUK+t+EuW2IWuhsQ==", "dev": true }, + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "acorn-jsx": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", + "dev": true + }, "ajv": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", @@ -978,6 +1181,23 @@ } } }, + "ansi-escapes": { + "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" + }, + "dependencies": { + "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 + } + } + }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -1128,6 +1348,17 @@ "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", "dev": true }, + "array-includes": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", + "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0", + "is-string": "^1.0.5" + } + }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", @@ -1135,6 +1366,16 @@ "dev": true, "optional": true }, + "array.prototype.flat": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", + "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -1157,6 +1398,12 @@ "dev": true, "optional": true }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async-each": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", @@ -1195,6 +1442,31 @@ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", "dev": true }, + "babel-eslint": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz", + "integrity": "sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, "babel-plugin-dynamic-import-node": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", @@ -1557,6 +1829,12 @@ } } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", @@ -1596,6 +1874,12 @@ "supports-color": "^5.3.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "chokidar": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", @@ -1660,6 +1944,21 @@ "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", "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" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -1800,6 +2099,12 @@ "xdg-basedir": "^3.0.0" } }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", @@ -1912,6 +2217,12 @@ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "defer-to-connect": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.0.tgz", @@ -2020,6 +2331,15 @@ } } }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", @@ -2268,18 +2588,500 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + }, + "dependencies": { + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + } + } + }, + "es-to-primitive": { + "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", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "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", + "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" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "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 + }, + "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" + } + }, + "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==", + "dev": true + }, + "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 + } + } + }, + "eslint-config-prettier": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.0.tgz", + "integrity": "sha512-AtndijGte1rPILInUdHjvKEGbIV06NuvPrqlIEaEaWtbtvJh464mDeyGMdZEQMsGvC0ZVkiex1fSNcC4HAbRGg==", + "dev": true, + "requires": { + "get-stdin": "^6.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + } + } + }, + "eslint-config-semistandard": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-15.0.0.tgz", + "integrity": "sha512-volIMnosUvzyxGkYUA5QvwkahZZLeUx7wcS0+7QumPn+MMEBbV6P7BY1yukamMst0w3Et3QZlCjQEwQ8tQ6nug==", + "dev": true + }, + "eslint-config-standard": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz", + "integrity": "sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", + "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-module-utils": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz", + "integrity": "sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "pkg-dir": "^2.0.0" + } + }, + "eslint-plugin-es": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz", + "integrity": "sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ==", + "dev": true, + "requires": { + "eslint-utils": "^1.4.2", + "regexpp": "^3.0.0" + }, + "dependencies": { + "regexpp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz", + "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz", + "integrity": "sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "array.prototype.flat": "^1.2.1", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.1", + "has": "^1.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.0", + "read-pkg-up": "^2.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + } + }, + "resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz", + "integrity": "sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ==", + "dev": true, + "requires": { + "eslint-plugin-es": "^2.0.0", + "eslint-utils": "^1.4.2", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "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 + } + } + }, + "eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true + }, + "eslint-plugin-standard": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz", + "integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==", + "dev": true + }, + "eslint-scope": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", + "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", + "dev": true, + "requires": { + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -2368,6 +3170,28 @@ } } }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", @@ -2469,6 +3293,12 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fd-slicer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", @@ -2478,6 +3308,24 @@ "pend": "~1.2.0" } }, + "figures": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -2531,6 +3379,34 @@ } } }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -3152,6 +4028,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -3290,6 +4172,15 @@ "har-schema": "^2.0.0" } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -3375,6 +4266,22 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "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", + "resolve-from": "^4.0.0" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -3406,18 +4313,98 @@ "wrappy": "1" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", - "dev": true - }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", + "dev": true + }, + "inquirer": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz", + "integrity": "sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "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 + }, + "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 + }, + "string-width": { + "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": { + "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" + } + } + } + }, + "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" + }, + "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 + } + } + } + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -3472,6 +4459,12 @@ "dev": true, "optional": true }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -3503,6 +4496,12 @@ } } }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -3535,8 +4534,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "optional": true + "dev": true }, "is-finite": { "version": "1.0.2", @@ -3561,7 +4559,6 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, - "optional": true, "requires": { "is-extglob": "^2.1.1" } @@ -3629,12 +4626,42 @@ "isobject": "^3.0.1" } }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "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.1" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -3743,6 +4770,12 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -3818,6 +4851,16 @@ "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", "dev": true }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -3991,6 +5034,12 @@ "mime-db": "1.43.0" } }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, "mimic-response": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", @@ -4050,6 +5099,12 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, "nan": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", @@ -4077,6 +5132,18 @@ "to-regex": "^3.0.1" } }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, "node-releases": { "version": "1.1.45", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.45.tgz", @@ -4203,6 +5270,12 @@ } } }, + "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-keys": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", @@ -4249,6 +5322,18 @@ "isobject": "^3.0.1" } }, + "object.values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", + "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4258,6 +5343,35 @@ "wrappy": "1" } }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "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.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, "p-cancelable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", @@ -4314,6 +5428,15 @@ } } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", @@ -4411,6 +5534,60 @@ "pinkie": "^2.0.0" } }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -4418,6 +5595,12 @@ "dev": true, "optional": true }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, "prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", @@ -4446,6 +5629,12 @@ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "progress-stream": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", @@ -4642,6 +5831,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "regexpu-core": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", @@ -4777,6 +5972,12 @@ "path-parse": "^1.0.6" } }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -4793,6 +5994,16 @@ "lowercase-keys": "^1.0.0" } }, + "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" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -4809,6 +6020,24 @@ "glob": "^7.1.3" } }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "rxjs": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -4928,6 +6157,25 @@ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "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 + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -5201,6 +6449,26 @@ "strip-ansi": "^3.0.0" } }, + "string.prototype.trimleft": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", + "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -5267,6 +6535,70 @@ "has-flag": "^3.0.0" } }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", + "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.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 + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", + "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": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "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" + } + } + } + }, "temp-file": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.4.tgz", @@ -5305,12 +6637,24 @@ "execa": "^0.7.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "throttleit": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", "dev": true }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, "through2": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", @@ -5347,6 +6691,15 @@ } } }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -5438,6 +6791,12 @@ "utf8-byte-length": "^1.0.1" } }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -5453,6 +6812,15 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-fest": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", @@ -5642,6 +7010,12 @@ "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", "dev": true }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -5720,6 +7094,12 @@ } } }, + "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 + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -5771,6 +7151,15 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", diff --git a/package.json b/package.json index 346d3028..aa122f28 100644 --- a/package.json +++ b/package.json @@ -6,13 +6,23 @@ "devDependencies": { "@babel/cli": "^7.7.7", "@babel/core": "^7.7.7", + "@babel/plugin-proposal-class-properties": "^7.8.3", "@babel/plugin-transform-async-to-generator": "^7.7.4", "@babel/plugin-transform-regenerator": "^7.7.5", "@babel/preset-env": "^7.7.7", "@babel/runtime": "^7.7.7", + "babel-eslint": "^10.0.3", "electron": "^5.0.11", "electron-builder": "21.2.0", "electron-notarize": "^0.2.1", + "eslint": "^6.7.2", + "eslint-config-prettier": "^6.7.0", + "eslint-config-semistandard": "^15.0.0", + "eslint-config-standard": "^14.1.0", + "eslint-plugin-import": "^2.19.1", + "eslint-plugin-node": "^10.0.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1", "mime-types": "^2.1.26", "rimraf": "^3.0.0" },