diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..e8e7d692 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +flow-custom-typedefs/*.js \ No newline at end of file diff --git a/.flowconfig b/.flowconfig index f2d95fdb..945b5648 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,11 +1,12 @@ [ignore] .*/node_modules/polished/.* -./__tests__ +./__tests__/**.js [include] [libs] flow-typed +flow-custom-typedefs [lints] diff --git a/coverage.json b/coverage.json new file mode 100644 index 00000000..7841daa4 --- /dev/null +++ b/coverage.json @@ -0,0 +1,8 @@ +{ + "concurrentFiles": 1, + "globExcludePatterns": ["node_modules/**", "dist/*.js"], + "flowCommandPath": "./node_modules/.bin/flow", + "globIncludePatterns": ["app/**/*.js", "config/**/*.js", "services/**/*.js", "utils/**/*.js"], + "threshold": 70, + "reportTypes": ["html"] +} diff --git a/flow-custom-typedefs/electron-store.js b/flow-custom-typedefs/electron-store.js new file mode 100644 index 00000000..aa2a7c03 --- /dev/null +++ b/flow-custom-typedefs/electron-store.js @@ -0,0 +1,24 @@ +declare module 'electron-store' { + declare class ElectronStore { + constructor({ + defaults?: Object, + name?: string, + cwd?: string, + encryptionKey?: string | Buffer, + fileExtension?: string, + }): ElectronStore; + + set(key: string, value: string): void; + set(payload: Object): void; + get(key: string): string; + has(key: string): boolean; + delete(key: string): void; + clear(): void; + size: number; + store: Object; + path: string; + openInEditor(): void; + } + + declare export default typeof ElectronStore; +} diff --git a/flow-custom-typedefs/electron.js b/flow-custom-typedefs/electron.js new file mode 100644 index 00000000..1edc6098 --- /dev/null +++ b/flow-custom-typedefs/electron.js @@ -0,0 +1,959 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the LICENSE file in + * the root directory of this source tree. + * + * @flow + */ + +// The properties on this module depend on whether the importer is the main +// process or a renderer process. +declare module 'electron' { + // Main process: + declare var app: electron$app; + declare var autoUpdater: electron$autoUpdater; + // $FlowFixMe + declare var BrowserWindow: typeof electron$BrowserWindow; + declare var contentTracing: electron$contentTracing; + declare var dialog: electron$dialog; + declare var globalShortcut: electron$globalShortcut; + declare var ipcMain: electron$IpcMain; + // $FlowFixMe + declare var Menu: typeof electron$Menu; + // $FlowFixMe + declare var MenuItem: typeof electron$MenuItem; + declare var powerMonitor: electron$powerMonitor; + declare var powerSaveBlocker: electron$powerSaveBlocker; + declare var protocol: electron$protocol; + declare var session: electron$session; + declare var electron$Tray: typeof electron$Tray; + declare var webContents: electron$webContents; + + // Renderer process: + declare var desktopCapturer: electron$desktopCapturer; + declare var ipcRenderer: electron$IpcRenderer; + declare var remote: electron$remote; + declare var webFrame: electron$webFrame; + + // Both: + declare var clipboard: electron$clipboard; + declare var crashReporter: electron$crashReporter; + declare var nativeImage: electron$nativeImage; + declare var screen: electron$Screen; + declare var shell: electron$shell; + + declare type electron$BrowserWindow = electron$BrowserWindow; + declare type electron$Menu = electron$Menu; + declare type electron$MenuItem = electron$MenuItem; + declare type electron$NativeImage = electron$NativeImage; + declare type electron$Screen = electron$Screen; + declare type electron$WebContents = electron$WebContents; +} + +// very common struct +type electron$rect = { + x: number, + y: number, + width: number, + height: number, +}; + +//------------------------------------------------------------------------------ +// Custom DOM Elements +//------------------------------------------------------------------------------ + +/** + * https://github.com/electron/electron/blob/master/docs/api/file-object.md + */ + +// HTML5 File API but with a `path` attribute added. + +/** + * https://github.com/electron/electron/blob/master/docs/api/web-view-tag.md + */ + +declare class WebviewElement extends HTMLElement { + src: string; + nodeintegration: boolean; + disablewebsecurity: boolean; + + executeJavaScript(code: string, userGesture: ?boolean): void; + getTitle(): string; + // This used to be `getUrl`, but the old version was dropped in the electron bundled with Atom + // 1.12, and the new version exists at least in Atom 1.10.2 onward. + getURL(): string; + // Not sure when this was introduced + stop?: () => void; + insertCSS(code: string): void; + send(channel: string, ...args: Array): void; + openDevTools(): void; +} + +/** + * https://github.com/electron/electron/blob/master/docs/api/window-open.md + */ + +// window.open + +//------------------------------------------------------------------------------ +// Modules for the Main Process +//------------------------------------------------------------------------------ + +/** + * https://github.com/electron/electron/blob/master/docs/api/app.md + */ + +type electron$app = { + quit(): void, + exit(exitCode?: number): void, + relaunch(options?: { args?: Array, execPath?: string }): void, + isReady(): boolean, + focus(): void, + getAppPath(): string, + getPath(name: string): string, + setPath(name: string, path: string): void, + getVersion(): string, + getName(): string, + setName(name: string): void, + getLocale(): string, + makeSingleInstance(callback: (argv: Array, workingDirectory: string) => void): boolean, + releaseSingleInstance(): void, + disableHardwareAcceleration(): void, + on(event: string, callback: () => any): void, +}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/auto-updater.md + */ + +type electron$autoUpdater = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/browser-window.md + */ + +type electron$BrowserWindowOptions = { + width?: number, + height?: number, + x?: number, + y?: number, + useContentSize?: boolean, + center?: boolean, + minWidth?: number, + minHeight?: number, + maxWidth?: number, + maxHeight?: number, + resizable?: boolean, + movable?: boolean, + minimizable?: boolean, + maximizable?: boolean, + closable?: boolean, + focusable?: boolean, + alwaysOnTop?: boolean, + fullscreen?: boolean, + fullscreenable?: boolean, + skipTaskbar?: boolean, + kiosk?: boolean, + title?: string, + icon?: electron$NativeImage, + show?: boolean, + frame?: boolean, + parent?: electron$BrowserWindow, + modal?: boolean, + acceptFirstMouse?: boolean, + disableAutoHideCursor?: boolean, + autoHideMenuBar?: boolean, + enableLargerThanScreen?: boolean, + backgroundColor?: string, + hasShadow?: boolean, + darkTheme?: boolean, + transparent?: boolean, + type?: + | 'desktop' + | 'dock' + | 'toolbar' + | 'splash' + | 'notification' + /* macOS */ + | 'desktop' + | 'textured' + /* Windows */ + | 'toolbar', + titleBarStyle?: 'default' | 'hidden' | 'hidden-inset', + thickFrame?: boolean, + webPreferences?: electron$BrowserWindowWebPreferences, +}; + +type electron$BrowserWindowWebPreferences = { + nodeIntegration?: boolean, + preload?: string, + session?: electron$session, + partition?: string, + zoomFactor?: number, + javascript?: boolean, + webSecurity?: boolean, + allowDisplayingInsecureContent?: boolean, + allowRunningInsecureContent?: boolean, + images?: boolean, + textAreasAreResizable?: boolean, + webgl?: boolean, + webaudio?: boolean, + plugins?: boolean, + experimentalFeatures?: boolean, + experimentalCanvasFeatures?: boolean, + scrollBounce?: boolean, + blinkFeatures?: string, + disableBlinkFeatures?: string, + defaultFontFamily?: { + standard?: string, + serif?: string, + sansSerif?: string, + monospace?: string, + }, + defaultFontSize?: number, + defaultMonospaceFontSize?: number, + minimumFontSize?: number, + defaultEncoding?: string, + backgroundThrottling?: boolean, + offscreen?: boolean, +}; + +type electron$BrowserWindowEvents = + | 'page-title-updated' + | 'close' + | 'closed' + | 'unresponsive' + | 'responsive' + | 'blur' + | 'focus' + | 'show' + | 'hide' + | 'ready-to-show' + | 'maximize' + | 'unmaximize' + | 'minimize' + | 'restore' + | 'resize' + | 'move' + | 'moved' + | 'enter-full-screen' + | 'leave-full-screen' + | 'enter-html-full-screen' + | 'leave-html-full-screen' + | 'context-menu' + | 'app-command' // Windows + | 'scroll-touch-begin' // macOS + | 'scroll-touch-end' // macOS + | 'swipe'; // macOS + +type electron$BrowserWindowListener = ( + event: electron$BrowserWindowEvents, + callback: (event: Object, ...args: Array) => void, +) => electron$BrowserWindow; + +declare class electron$BrowserWindow { + constructor(options: electron$BrowserWindowOptions): void; + on: electron$BrowserWindowListener; + once: electron$BrowserWindowListener; + removeAllListeners(event?: electron$BrowserWindowEvents): electron$BrowserWindow; + removeListener(event?: electron$BrowserWindowEvents, callback: Function): electron$BrowserWindow; + send(channel: string, ...args: Array): void; + + static getAllWindows(): Array; + static getFocusedWindow(): ?electron$BrowserWindow; + static fromWebContents(webContents: electron$WebContents): ?electron$BrowserWindow; + static fromId(id: number): ?electron$BrowserWindow; + static addDevToolsExtension(path: string): void; + static removeDevToolsExtension(name: string): void; + static getDevToolsExtensions(): { [name: string]: { [name: string]: string } }; + + webContents: electron$WebContents; + id: number; + destroy(): void; + close(): void; + focus(): void; + blur(): void; + isFocused(): boolean; + show(): void; + showInactive(): void; + hide(): void; + isVisible(): boolean; + isModal(): boolean; + maximize(): void; + unmaximize(): void; + isMaximized(): boolean; + minimize(): void; + restore(): void; + isMinimized(): boolean; + setFullScreen(flag: boolean): void; + isFullScreen(): boolean; + setAspectRatio(aspectRatio: number, extraSize?: { width: number, height: number }): void; // macOS + setBounds(options: electron$rect, /* macOS */ animate?: boolean): void; + getBounds(): electron$rect; + setSize(width: number, height: number, /* macOS */ animate?: boolean): void; + getSize(): [number, number]; + setContentSize(width: number, height: number, /* macOS */ animate?: boolean): void; + getContentSize(): [number, number]; + setMinimumSize(width: number, height: number): void; + getMinimumSize(): [number, number]; + setMaximumSize(width: number, height: number): void; + getMaximumSize(): [number, number]; + setResizable(resizable: boolean): void; + isResizable(): boolean; + setMovable(movable: boolean): void; // macOS Windows + isMovable(): boolean; // macOS Windows + setMinimizable(minimizable: boolean): void; // macOS Windows + isMinimizable(): boolean; // macOS Windows + setMaximizable(maximizable: boolean): void; // macOS Windows + isMaximizable(): boolean; // macOS Windows + setFullScreenable(fullscreenable: boolean): void; + isFullScreenable(): boolean; + setClosable(closable: boolean): void; // macOS Windows + isClosable(): boolean; // macOS Windows + setAlwaysOnTop(flag: boolean): void; + isAlwaysOnTop(): boolean; + center(): void; + setPosition(x: number, y: number, /* macOS */ animate?: boolean): void; + getPosition(): [number, number]; + setTitle(title: string): void; + getTitle(): string; + setSheetOffset(offsetY: number, offsetX?: number): void; // macOS + flashFrame(flag: boolean): void; + setSkipTaskbar(skip: boolean): void; + setKiosk(flag: boolean): void; + isKiosk(): boolean; + getNativeWindowHandle(): Buffer; + hookWindowMessage(message: number, callback: Function): void; // Windows + isWindowMessageHooked(message: number): boolean; // Windows + unhookWindowMessage(message: number): void; // Windows + unhookAllWindowMessages(): void; // Windows + setRepresentedFilename(filename: string): void; // macOS + getRepresentedFilename(): string; // macOS + setDocumentEdited(edited: boolean): void; // macOS + isDocumentEdited(): boolean; // macOS + focusOnWebView(): void; + blurWebView(): void; + capturePage(rect: electron$rect, callback: (image: electron$NativeImage) => void): void; + capturePage(callback: (image: electron$NativeImage) => void): void; + loadURL( + url: string, + options?: { httpReferrer?: string, userAgent?: string, extraHeaders?: string }, + ): void; + reload(): void; + setMenu(menu: ?electron$Menu): void; // Linux Windows + setProgressBar(progress: number): void; + setOverlayIcon(overlay: electron$NativeImage, description: string): void; // Windows + setHasShadow(hasShadow: boolean): void; // macOS + hasShadow(): boolean; // macOS + setThumbarButtons( + buttons: Array<{ + icon: electron$NativeImage, + click: Function, + tooltip?: string, + flags?: Array< + 'enabled' | 'disabled' | 'dismissonclick' | 'nobackground' | 'hidden' | 'noninteractive', + >, + }>, + ): void; // Windows + setThumbnailClip(region: electron$rect): void; // Windows + showDefinitionForSelection(): void; // macOS + setIcon(icon: electron$NativeImage): void; // Windows Linux + setAutoHideMenuBar(hide: boolean): void; + isMenuBarAutoHide(): boolean; + setMenuBarVisibility(visible: boolean): void; + isMenuBarVisible(): boolean; + setVisibleOnAllWorkspaces(visible: boolean): void; + isVisibleOnAllWorkspaces(): boolean; + setIgnoreMouseEvents(ignore: boolean): void; + setContentProtection(enable: boolean): void; // macOS Windows + setFocusable(focusable: boolean): void; // Windows + setParentWindow(parent: electron$BrowserWindow): void; // Linux macOS + getParentWindow(): ?electron$BrowserWindow; + getChildWindows(): Array; + + // Atom sets this during window setup (see: src/main-process/atom-window.coffee). + loadSettings?: Object; +} + +/** + * https://github.com/electron/electron/blob/master/docs/api/content-tracing.md + */ + +type electron$contentTracing = { + startRecording( + options: { categoryFilter: string, traceOptions: string }, + callback: () => mixed, + ): boolean, + + stopRecording(resultFilePath: ?string, callback: (resultFilePath: string) => mixed): void, +}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/dialog.md + */ + +type electron$dialog = { + showOpenDialog( + browserWindow?: electron$BrowserWindow, + options: electron$dialogOpenOptions, + callback?: Function, + ): Array, + showSaveDialog( + browserWindow?: electron$BrowserWindow, + options: electron$dialogSaveOptions, + callback?: Function, + ): string, + showMessageBox( + browserWindow?: electron$BrowserWindow, + options: electron$dialogMessageBoxOptions, + callback?: Function, + ): number, + showErrorBox(title: string, content: string): void, +}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/dialog.md + * See `dialog.showOpenDialog()` + */ + +type electron$dialogOpenOptions = { + title?: string, + defaultPath?: string, + buttonLabel?: string, + filters?: Array, + properties?: Array, +}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/dialog.md + * See `dialog.showSaveDialog()` + */ + +type electron$dialogSaveOptions = { + title?: string, + defaultPath?: string, + buttonLabel?: string, + filters?: Array, +}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/dialog.md + * See `dialog.showMessageBox()` + */ + +type electron$dialogMessageBoxOptions = { + type?: string, + buttons?: Array, + defaultId?: number, + title?: string, + message?: string, + detail?: string, + icon?: electron$NativeImage, + cancelId?: number, + noLink?: boolean, +}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/global-shortcut.md + */ + +type electron$globalShortcut = { + register: (string, () => void) => boolean, + isRegistered: string => boolean, + unregister: string => void, + unregisterAll: () => void, +}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/ipc-main.md + */ + +declare class electron$IpcMain {} + +/** + * https://github.com/electron/electron/blob/master/docs/api/menu.md + */ + +declare class electron$Menu { + static setApplicationMenu(menu: electron$Menu): void; + static getApplicationMenu(): ?electron$Menu; + static sendActionToFirstResponder(action: string): void; + static buildFromTemplate(templates: Array): electron$Menu; + popup( + browserWindow: electron$BrowserWindow, + x?: number, + y?: number, + positioningItem?: number, + ): void; + popup(x?: number, y?: number, positioningItem?: number): void; + append(menuItem: electron$MenuItem): void; + insert(pos: number, menuItem: electron$MenuItem): void; + items: Array; +} + +/** + * https://github.com/electron/electron/blob/master/docs/api/menu-item.md + */ + +type electron$MenuItemOptions = { + click?: ( + menuItem: electron$MenuItem, + browserWindow: electron$BrowserWindow, + event: Object, + ) => void, + role?: + | 'undo' + | 'redo' + | 'cut' + | 'copy' + | 'paste' + | 'pasteandmatchstyle' + | 'selectall' + | 'delete' + | 'minimize' + | 'close' + | 'quit' + | 'togglefullscreen' + // macOS-only + | 'about' + | 'hide' + | 'hideothers' + | 'unhide' + | 'front' + | 'zoom' + | 'window' + | 'help' + | 'services', + type?: 'normal' | 'separator' | 'submenu' | 'checkbox' | 'radio', + label?: string, + sublabel?: string, + accelerator?: string, + icon?: electron$NativeImage, + enabled?: boolean, + visible?: boolean, + checked?: boolean, + submenu?: electron$MenuItem | electron$MenuItemOptions, + id?: string, + position?: string, +}; + +declare class electron$MenuItem { + constructor(options: electron$MenuItemOptions): void; + enabled: boolean; + visible: boolean; + checked: boolean; +} + +/** + * https://github.com/electron/electron/blob/master/docs/api/power-monitor.md + */ + +type electron$powerMonitor = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/power-save-blocker.md + */ + +type electron$powerSaveBlocker = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/protocol.md + */ + +type electron$protocol = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/session.md + */ + +type electron$session = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/system-preferences.md + */ + +type electron$systemPreferences = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/tray.md + */ + +declare class electron$Tray {} + +/** + * https://github.com/electron/electron/blob/master/docs/api/web-contents.md + */ + +type electron$InputEventModifiers = Array< + | 'shift' + | 'control' + | 'alt' + | 'meta' + | 'isKeypad' + | 'isAutoRepeat' + | 'leftButtonDown' + | 'middleButtonDown' + | 'rightButtonDown' + | 'capsLock' + | 'numLock' + | 'left' + | 'right', +>; + +declare class electron$WebContents extends events$EventEmitter { + loadURL( + url: string, + options?: { httpReferrer?: string, userAgent?: string, extraHeaders?: string }, + ): void; + downloadURL(url: string): void; + getURL(): string; + getTitle(): string; + isDestroyed(): boolean; + isFocused(): boolean; + isLoading(): boolean; + isLoadingMainFrame(): boolean; + isWaitingForResponse(): boolean; + stop(): void; + reload(): void; + reloadIgnoringCache(): void; + canGoBack(): boolean; + canGoForward(): boolean; + canGoToOffset(offset: number): boolean; + clearHistory(): void; + goBack(): void; + goForward(): void; + goToIndex(index: number): void; + goToOffset(index: number): void; + isCrashed(): boolean; + setUserAgent(userAgent: string): void; + getUserAgent(): string; + insertCSS(css: string): void; + // Keep `result` as mixed (and not any) to make this unsafe function less so. + executeJavaScript(code: string, callback: (result: mixed) => void): void; + executeJavaScript(code: string, userGesture?: boolean, callback?: (result: mixed) => void): void; + setAudioMuted(muted: boolean): void; + isAudioMuted(): boolean; + setZoomFactor(factor: number): void; + getZoomFactor(callback: (factor: number) => void): void; + setZoomLevel(level: number): void; + getZoomLevel(callback: (level: number) => void): void; + setZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + setLayoutZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; + undo(): void; + redo(): void; + cut(): void; + copy(): void; + copyImageAt(x: number, y: number): void; + paste(): void; + pasteAndMatchStyle(): void; + delete(): void; + selectAll(): void; + unselect(): void; + replace(text: string): void; + replaceMisspelling(text: string): void; + insertText(text: string): void; + inserfindInPagetText( + text: string, + options?: { + forward?: boolean, + findNext?: boolean, + matchCase?: boolean, + wordStart?: boolean, + medialCapitalAsWordStart?: boolean, + }, + ): void; + stopFindInPage(action: 'clearSelection' | 'keepSelection' | 'activateSelection'): void; + capturePage(rect: electron$rect, callback: (image: electron$NativeImage) => void): void; + capturePage(callback: (image: electron$NativeImage) => void): void; + hasServiceWorker(callback: (result: boolean) => void): void; + unregisterServiceWorker(callback: (result: boolean) => void): void; + print(options?: { silent?: boolean, printBackground?: boolean }): void; + printToPDF( + options: { + marginsType: number, + pageSize: string, + pageSize: string, + printBackground: boolean, + printSelectionOnly: boolean, + landscape: boolean, + }, + callback: (err: ?mixed, data: ?Buffer) => void, + ): void; + addWorkSpace(path: string): void; + removeWorkSpace(path: string): void; + openDevTools(options?: { mode: 'right' | 'bottom' | 'undocked' | 'detach' }): void; + closeDevTools(): void; + isDevToolsOpened(): boolean; + isDevToolsFocused(): boolean; + toggleDevTools(): void; + inspectElement(x: number, y: number): void; + inspectServiceWorker(): void; + send(channel: string, ...args: Array): void; + enableDeviceEmulation(parameters: { + screenPosition?: 'desktop' | 'mobile', + screenSize: { width: number, height: number }, + viewPosition?: { x: number, y: number }, + deviceScaleFactor?: number, + viewSize?: { width: number, height: number }, + fitToView?: boolean, + offset?: { x: number, y: number }, + scale?: number, + }): void; + disableDeviceEmulation(): void; + sendInputEvent( + event: + | { + type: 'keyDown' | 'keyUp' | 'char', + modifiers?: electron$InputEventModifiers, + keyCode: string, + } + | { + type: 'mouseDown' | 'mouseUp' | 'mouseEnter' | 'mouseLeave' | 'contextMenu', + modifiers?: electron$InputEventModifiers, + x: number, + y: number, + button: 'left' | 'middle' | 'right', + globalX: number, + globalY: number, + movementX: number, + movementY: number, + clickCount: number, + } + | { + type: 'mouseWheel', + modifiers?: electron$InputEventModifiers, + x: number, + y: number, + button: 'left' | 'middle' | 'right', + globalX: number, + globalY: number, + movementX: number, + movementY: number, + clickCount: number, + deltaX: number, + deltaY: number, + wheelTicksX: number, + wheelTicksY: number, + accelerationRatioX: number, + accelerationRatioY: number, + hasPreciseScrollingDeltas: boolean, + canScroll: boolean, + }, + ): void; + beginFrameSubscription(callback: (frameBuffer: Buffer, dirtyRect: electron$rect) => void): void; + beginFrameSubscription( + onlyDirty?: boolean, + callback: (frameBuffer: Buffer, dirtyRect: electron$rect) => void, + ): void; + endFrameSubscription(): void; + startDrag(item: { file: string, icon: electron$NativeImage }): void; + savePage( + fullPath: string, + saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML', + callback: (error: ?mixed) => void, + ): void; + showDefinitionForSelection(): void; + isOffscreen(): boolean; + startPainting(): void; + stopPainting(): void; + isPainting(): boolean; + setFrameRate(fps: number): void; + getFrameRate(): ?number; + + id: number; + session: electron$session; + hostWebContents: ?electron$WebContents; + devToolsWebContents: ?electron$WebContents; + debugger: ?electron$Debugger; +} + +declare class electron$Debugger extends events$EventEmitter { + attach(protocolVersion?: string): void; + isAttached(): boolean; + detach(): void; + sendCommand(method: string, callback?: (error: ?mixed, result: ?mixed) => void): void; + sendCommand( + method: string, + commandParams?: Object, + callback?: (error: ?mixed, result: ?mixed) => void, + ): void; +} + +type electron$webContents = { + getAllWebContents(): Array, + getFocusedWebContents: ?electron$WebContents, + fromId(id: number): ?electron$WebContents, +}; + +//------------------------------------------------------------------------------ +// Modules for the Renderer Process (Web Page) +//------------------------------------------------------------------------------ + +/** + * https://github.com/electron/electron/blob/master/docs/api/desktop-capturer.md + */ + +type electron$desktopCapturer = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md + */ + +declare class electron$IpcRenderer { + on(channel: string, callback: (...args: Array) => void): electron$IpcRenderer; + once(channel: string, callback: (...args: Array) => void): electron$IpcRenderer; + removeListener(channel: string, callback: (...args: Array) => void): electron$IpcRenderer; + removeAllListeners(channel?: string): electron$IpcRenderer; + send(channel: string, ...args: Array): void; + sendSync(channel: string, ...args: Array): void; + sendToHost(channel: string, ...args: Array): void; +} + +/** + * https://github.com/electron/electron/blob/master/docs/api/remote.md + */ + +type electron$remote = { + // main process built-in modules: + app: electron$app, + autoUpdater: electron$autoUpdater, + BrowserWindow: typeof electron$BrowserWindow, + contentTracing: electron$contentTracing, + dialog: electron$dialog, + globalShortcut: electron$globalShortcut, + ipcMain: electron$IpcMain, + Menu: typeof electron$Menu, + MenuItem: typeof electron$MenuItem, + powerMonitor: electron$powerMonitor, + powerSaveBlocker: electron$powerSaveBlocker, + protocol: electron$protocol, + session: electron$session, + electron$Tray: typeof electron$Tray, + webContents: electron$webContents, + // methods: + require(module: string): any, + getCurrentWindow(): electron$BrowserWindow, + getCurrentWebContents(): electron$WebContents, + getGlobal(name: string): ?mixed, + process: typeof process, +}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/web-frame.md + */ + +type electron$webFrame = { + registerURLSchemeAsBypassingCSP(scheme: string): void, +}; + +//------------------------------------------------------------------------------ +// Modules for Both Processes +//------------------------------------------------------------------------------ + +/** + * https://github.com/electron/electron/blob/master/docs/api/clipboard.md + */ + +type electron$clipboard = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/crash-reporter.md + */ + +type electron$crashReporter = {}; + +/** + * https://github.com/electron/electron/blob/master/docs/api/native-image.md + */ + +type electron$nativeImage = { + createEmpty(): electron$NativeImage, + createFromPath(path: string): electron$NativeImage, + createFromBuffer(buffer: Buffer, scaleFactor?: number): electron$NativeImage, + createFromDataURL(dataURL: string): electron$NativeImage, +}; + +declare class electron$NativeImage { + toPNG(): Uint8Array; + toJPEG(quality: number): Uint8Array; + toBitmap(): Uint8Array; + toDataURL(): string; + getNativeHandle(): Uint8Array; + isEmpty(): boolean; + getSize(): { width: number, height: number }; + setTemplateImage(option: boolean): void; + isTemplateImage(): boolean; + // Deprecated, but Atom is behind - so keep them around. + toPng(): Uint8Array; + toJpeg(quality: number): Uint8Array; + toDataUrl(): string; +} + +/** + * https://github.com/electron/electron/blob/master/docs/api/screen.md + */ + +type electron$Display = { + id: number, + rotation: 0 | 90 | 180 | 270, + scaleFactor: number, + touchSupport: 'available' | 'unavailable' | 'unknown', + bounds: electron$rect, + size: { height: number, width: number }, + workArea: electron$rect, + workAreaSize: { height: number, width: number }, +}; + +type electron$DisplayEvents = 'display-added' | 'display-removed' | 'display-metrics-changed'; + +type electron$ScreenListener = ( + event: electron$DisplayEvents, + callback: ( + event: Object, + display: electron$Display, + changedMetrics?: Array<'bounds' | 'workArea' | 'scaleFactor' | 'rotation'>, + ) => void, +) => electron$Screen; + +declare class electron$Screen { + on: electron$ScreenListener; + once: electron$ScreenListener; + removeAllListeners(event?: electron$DisplayEvents): electron$Screen; + removeListener(event?: electron$DisplayEvents, callback: Function): electron$Screen; + getCursorScreenPoint(): { x: number, y: number }; + getPrimaryDisplay(): electron$Display; + getAllDisplays(): Array; + getDisplayNearestPoint(point: { x: number, y: number }): electron$Display; + getDisplayMatching(rect: electron$rect): electron$Display; +} + +/** + * https://github.com/electron/electron/blob/master/docs/api/shell.md + */ + +type electron$shell = { + showItemInFolder(fullPath: string): void, + openItem(fullPath: string): void, + openExternal(url: string, options?: { activate: boolean }): void, + moveItemToTrash(fullPath: string): boolean, + beep(): void, + // Windows-only + writeShortcutLink( + shortcutPath: string, + operation?: 'create' | 'update' | 'replace', + options?: { + target: string, + cwd?: string, + args?: string, + description?: string, + icon?: string, + iconIndex?: number, + appUserModelId?: string, + }, + ): void, + // Windows-only + readShortcutLink(shortcutPath: string): void, +}; diff --git a/flow-custom-typedefs/eres.js b/flow-custom-typedefs/eres.js new file mode 100644 index 00000000..0ac23611 --- /dev/null +++ b/flow-custom-typedefs/eres.js @@ -0,0 +1,3 @@ +declare module 'eres' { + declare module.exports: (Promise) => Promise<[?Error, T]>; +} diff --git a/flow-custom-typedefs/lodash.flow.js b/flow-custom-typedefs/lodash.flow.js new file mode 100644 index 00000000..9a8bda4f --- /dev/null +++ b/flow-custom-typedefs/lodash.flow.js @@ -0,0 +1,3 @@ +declare module 'lodash.flow' { + declare module.exports: $ComposeReverse & ((funcs?: Array) => Function); +} diff --git a/flow-custom-typedefs/lodash.groupby.js b/flow-custom-typedefs/lodash.groupby.js new file mode 100644 index 00000000..e39fbe9f --- /dev/null +++ b/flow-custom-typedefs/lodash.groupby.js @@ -0,0 +1,15 @@ +declare module 'lodash.groupby' { + declare type _ValueOnlyIteratee = (value: T) => mixed; + declare type ValueOnlyIteratee = _ValueOnlyIteratee | string; + + declare type GroupBy = ( + array: $ReadOnlyArray, + iteratee?: ?ValueOnlyIteratee, + ) => { [key: V]: Array } & ((array: void | null, iteratee?: ?ValueOnlyIteratee) => {}) & + (( + object: T, + iteratee?: ValueOnlyIteratee, + ) => { [key: V]: Array }); + + declare export default GroupBy; +} diff --git a/package.json b/package.json index c6f50259..c4d6451d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build": "rm -rf build && webpack --config config/webpack-prod.config.js --mode production --env.NODE_ENV=production", "lint:precommit": "eslint ./app/", "flow:precommit": "glow", - "flow:coverage": "flow-coverage-report -t html -i 'app/**/*.js' -x 'dist/*.js' --threshold 70", + "flow:coverage": "flow-coverage-report --config ./coverage.json", "flow:report": "yarn flow:coverage && cd ./flow-coverage && open index.html", "electron:dev": "electron -r @babel/register .", "electron:prepare": "yarn icon:build && rm -rf dist && mkdir dist", @@ -66,7 +66,7 @@ "eslint-plugin-react": "^7.12.4", "file-loader": "^2.0.0", "flow-bin": "^0.91.0", - "flow-coverage-report": "^0.6.0", + "flow-coverage-report": "^0.6.1", "flow-typed": "^2.5.1", "glow": "^1.2.2", "html-webpack-plugin": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index 21c59c1f..b796c62d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1412,6 +1412,15 @@ vue-template-compiler "^2.0.0-alpha.8" vue-template-es2015-compiler "^1.4.2" +"@rpl/badge-up@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@rpl/badge-up/-/badge-up-2.2.0.tgz#79a5ccf72bdb1777390bb7e4caa08dc42d57dd9a" + integrity sha512-ylcyuw/fttO3gJPF04B257HK5u14xhCnWhN6JuW1Z7236lNj8WU10xxWcPI471tNqqE9ksJ3ApoJigXW8WjDKQ== + dependencies: + css-color-names "~0.0.3" + dot "^1.1.1" + svgo "^1.1.1" + "@sheerun/mutationobserver-shim@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz#8013f2af54a2b7d735f71560ff360d3a8176a87b" @@ -2123,14 +2132,6 @@ argparse@^1.0.7, argparse@^1.0.9: dependencies: sprintf-js "~1.0.2" -"argparse@~ 0.1.11": - version "0.1.16" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c" - integrity sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw= - dependencies: - underscore "~1.7.0" - underscore.string "~2.4.0" - args@^2.3.0: version "2.6.1" resolved "https://registry.yarnpkg.com/args/-/args-2.6.1.tgz#b2590ed4168cd31b62444199bdc5166bb1920c2f" @@ -3092,15 +3093,6 @@ babylon@^6.17.0, babylon@^6.18.0: resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== -badge-up@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/badge-up/-/badge-up-2.3.0.tgz#72fff694a32d44aa14031e72889e0fc55b53058b" - integrity sha1-cv/2lKMtRKoUAx5yiJ4PxVtTBYs= - dependencies: - css-color-names "~0.0.3" - dot "~1.0.2" - svgo "~0.4.5" - bail@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.3.tgz#63cfb9ddbac829b02a3128cd53224be78e6c21a3" @@ -4194,13 +4186,6 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= -coa@~0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/coa/-/coa-0.4.1.tgz#baf6f49c7ad9f20c597af39b3fc1e5090fe8838b" - integrity sha1-uvb0nHrZ8gxZevObP8HlCQ/og4s= - dependencies: - q "~0.9.6" - coa@~1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd" @@ -4334,11 +4319,6 @@ colors@^1.0.3, colors@^1.1.2: resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.2.tgz#2df8ff573dfbf255af562f8ce7181d6b971a359b" integrity sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ== -colors@~0.6.0: - version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" - integrity sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w= - colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -6029,10 +6009,10 @@ dot-prop@^4.1.0, dot-prop@^4.1.1, dot-prop@^4.2.0: dependencies: is-obj "^1.0.0" -dot@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dot/-/dot-1.0.3.tgz#f8750bfb6b03c7664eb0e6cb1eb4c66419af9427" - integrity sha1-+HUL+2sDx2ZOsObLHrTGZBmvlCc= +dot@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/dot/-/dot-1.1.2.tgz#c7377019fc4e550798928b2b9afeb66abfa1f2f9" + integrity sha1-xzdwGfxOVQeYkosrmv62ar+h8vk= dotenv-expand@^4.2.0: version "4.2.0" @@ -6743,11 +6723,6 @@ esprima@^4.0.0, esprima@~4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -"esprima@~ 1.0.2": - version "1.0.4" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" - integrity sha1-n1V+CPw7TSbs6d00+Pv0drYlha0= - esquery@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" @@ -7324,14 +7299,14 @@ flow-bin@^0.91.0: resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.91.0.tgz#f5c89729f74b2ccbd47df6fbfadbdcc89cc1e478" integrity sha512-j+L+xNiUYnZZ27MjVI0y2c9474ZHOvdSQq0Tjwh56mEA7tfxYqp5Dcb6aZSwvs3tGMTjCrZow9aUlZf3OoRyDQ== -flow-coverage-report@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/flow-coverage-report/-/flow-coverage-report-0.6.0.tgz#3bab30921f14ef798d709902048205bd7611ec43" - integrity sha512-Tr94Db/8xXhaaEeO5knE5iGZ/UxzmuVPqb4F2pcOgKv3R6/9kLVprIcORZJnxKPiPvF6f56JAoNx0TdkDCJUxA== +flow-coverage-report@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/flow-coverage-report/-/flow-coverage-report-0.6.1.tgz#b7b3458093dba1aebf48288b251877bb6861fe5b" + integrity sha512-AUMuC4rocbGcyhKG8oINN4qKaJ2aYbhZQlyk5ro9/TcQ1+gdcy/O0OM9iilEmL2uJraHkFpwo9dCfiJbvRwQcA== dependencies: + "@rpl/badge-up" "2.2.0" array.prototype.find "2.0.4" babel-runtime "6.23.0" - badge-up "2.3.0" flow-annotation-check "1.8.1" glob "7.1.1" minimatch "3.0.4" @@ -9875,14 +9850,6 @@ js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.7.0, js-yaml@^3.9.0: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@~2.1.0: - version "2.1.3" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-2.1.3.tgz#0ffb5617be55525878063d7a16aee7fdd282e84c" - integrity sha1-D/tWF75VUlh4Bj16Fq7n/dKC6Ew= - dependencies: - argparse "~ 0.1.11" - esprima "~ 1.0.2" - js-yaml@~3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" @@ -13363,11 +13330,6 @@ q@^1.1.2, q@~1.5.0: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -q@~0.9.6: - version "0.9.7" - resolved "https://registry.yarnpkg.com/q/-/q-0.9.7.tgz#4de2e6cb3b29088c9e4cbc03bf9d42fb96ce2f75" - integrity sha1-TeLmyzspCIyeTLwDv51C+5bOL3U= - qr.js@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/qr.js/-/qr.js-0.0.0.tgz#cace86386f59a0db8050fa90d9b6b0e88a1e364f" @@ -14829,11 +14791,6 @@ sax@>=0.6.0, sax@^1.1.4, sax@^1.2.4, sax@~1.2.1, sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -sax@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" - integrity sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk= - scan-directory@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/scan-directory/-/scan-directory-1.0.0.tgz#46b6769dbd893d9bd7490ae9dcc43811a38b7fbb" @@ -15860,17 +15817,6 @@ svgo@^1.0.0, svgo@^1.1.1: unquote "~1.1.1" util.promisify "~1.0.0" -svgo@~0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.4.5.tgz#ba56155fb1733728956c01b405221ee7e789a2a4" - integrity sha1-ulYVX7FzNyiVbAG0BSIe5+eJoqQ= - dependencies: - coa "~0.4.0" - colors "~0.6.0" - js-yaml "~2.1.0" - sax "~0.6.0" - whet.extend "~0.9.9" - swap-case@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3" @@ -16466,16 +16412,6 @@ ulid@^2.3.0: resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== -underscore.string@~2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b" - integrity sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs= - -underscore@~1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" - integrity sha1-a7rwh3UA02vjTsqlhODbn+8DUgk= - unescape-js@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unescape-js/-/unescape-js-1.1.1.tgz#a4345e654b857c29fa66469e311ccaf2e93063bd"