Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

port app/index and it's referenced files to ts #4083

Merged
merged 2 commits into from
Dec 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/ext-modules.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare module 'git-describe' {
export function gitDescribe(...args: any[]): void;
}
1 change: 1 addition & 0 deletions app/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// Dummy file, required by tsc
64 changes: 45 additions & 19 deletions app/index.js → app/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Print diagnostic information for a few arguments instead of running Hyper.
if (['--help', '-v', '--version'].includes(process.argv[1])) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const {version} = require('./package');
const configLocation = process.platform === 'win32' ? `${process.env.userprofile}\\.hyper.js` : '~/.hyper.js';
//eslint-disable-next-line no-console
Expand All @@ -25,6 +26,7 @@ const checkSquirrel = () => {

// handle startup squirrel events
if (process.platform === 'win32') {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const systemContextMenu = require('./system-context-menu');

switch (process.argv[1]) {
Expand Down Expand Up @@ -53,16 +55,38 @@ import {gitDescribe} from 'git-describe';
import isDev from 'electron-is-dev';
import * as config from './config';

// Hack - this declararion doesn't work when put into ./ext-modules.d.ts for some reason so it's in this file for the time being
declare module 'electron' {
interface App {
config: typeof import('./config');
plugins: typeof import('./plugins');
getWindows: () => Set<BrowserWindow>;
getLastFocusedWindow: () => BrowserWindow | null;
windowCallback: (win: BrowserWindow) => void;
createWindow: (fn?: (win: BrowserWindow) => void, options?: Record<string, any>) => BrowserWindow;
setVersion: (version: string) => void;
}

type Server = import('./rpc').Server;
interface BrowserWindow {
uid: string;
sessions: Map<any, any>;
focusTime: number;
clean: () => void;
rpc: Server;
}
}

// set up config
config.setup();

import * as plugins from './plugins';
import {installCLI} from './utils/cli-install';
import * as AppMenu from './menus/menu';
import Window from './ui/window';
import {newWindow} from './ui/window';
import * as windowUtils from './utils/window-utils';

const windowSet = new Set([]);
const windowSet = new Set<BrowserWindow>([]);

// expose to plugins
app.config = config;
Expand All @@ -89,7 +113,7 @@ if (isDev) {
console.log('running in dev mode');

// Override default appVersion which is set from package.json
gitDescribe({customArguments: ['--tags']}, (error, gitInfo) => {
gitDescribe({customArguments: ['--tags']}, (error: any, gitInfo: any) => {
if (!error) {
app.setVersion(gitInfo.raw);
}
Expand All @@ -103,16 +127,30 @@ const url = `file://${resolve(isDev ? __dirname : app.getAppPath(), 'index.html'
//eslint-disable-next-line no-console
console.log('electron will open', url);

function installDevExtensions(isDev_: boolean) {
if (!isDev_) {
return Promise.resolve([]);
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const installer = require('electron-devtools-installer') as typeof import('electron-devtools-installer');

const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'] as const;
const forceDownload = Boolean(process.env.UPGRADE_EXTENSIONS);

return Promise.all(extensions.map(name => installer.default(installer[name], forceDownload)));
}

app.on('ready', () =>
installDevExtensions(isDev)
.then(() => {
function createWindow(fn, options = {}) {
function createWindow(fn?: (win: BrowserWindow) => void, options: Record<string, any> = {}) {
const cfg = plugins.getDecoratedConfig();

const winSet = config.getWin();
let [startX, startY] = winSet.position;

const [width, height] = options.size ? options.size : cfg.windowSize || winSet.size;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const {screen} = require('electron');

const winPos = options.position;
Expand Down Expand Up @@ -150,7 +188,7 @@ app.on('ready', () =>
[startX, startY] = config.windowDefaults.windowPosition;
}

const hwin = new Window({width, height, x: startX, y: startY}, cfg, fn);
const hwin = newWindow({width, height, x: startX, y: startY}, cfg, fn);
windowSet.add(hwin);
hwin.loadURL(url);

Expand Down Expand Up @@ -229,7 +267,7 @@ app.on('ready', () =>

app.on('open-file', (event, path) => {
const lastWindow = app.getLastFocusedWindow();
const callback = win => win.rpc.emit('open file', {path});
const callback = (win: BrowserWindow) => win.rpc.emit('open file', {path});
if (lastWindow) {
callback(lastWindow);
} else if (!lastWindow && {}.hasOwnProperty.call(app, 'createWindow')) {
Expand All @@ -243,7 +281,7 @@ app.on('open-file', (event, path) => {

app.on('open-url', (event, sshUrl) => {
const lastWindow = app.getLastFocusedWindow();
const callback = win => win.rpc.emit('open ssh', sshUrl);
const callback = (win: BrowserWindow) => win.rpc.emit('open ssh', sshUrl);
if (lastWindow) {
callback(lastWindow);
} else if (!lastWindow && {}.hasOwnProperty.call(app, 'createWindow')) {
Expand All @@ -254,15 +292,3 @@ app.on('open-url', (event, sshUrl) => {
app.windowCallback = callback;
}
});

function installDevExtensions(isDev_) {
if (!isDev_) {
return Promise.resolve();
}
const installer = require('electron-devtools-installer');

const extensions = ['REACT_DEVELOPER_TOOLS', 'REDUX_DEVTOOLS'];
const forceDownload = Boolean(process.env.UPGRADE_EXTENSIONS);

return Promise.all(extensions.map(name => installer.default(installer[name], forceDownload)));
}
17 changes: 10 additions & 7 deletions app/menus/menu.js → app/menus/menu.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Packages
import {app, dialog, Menu} from 'electron';
import {app, dialog, Menu, BrowserWindow} from 'electron';

// Utilities
import {getConfig} from '../config';
Expand All @@ -18,13 +18,16 @@ import {getRendererTypes} from '../utils/renderer-utils';
const appName = app.getName();
const appVersion = app.getVersion();

let menu_ = [];
let menu_: Menu;

export const createMenu = (createWindow, getLoadedPluginVersions) => {
export const createMenu = (
createWindow: (fn?: (win: BrowserWindow) => void, options?: Record<string, any>) => BrowserWindow,
getLoadedPluginVersions: () => {name: string; version: string}[]
) => {
const config = getConfig();
// We take only first shortcut in array for each command
const allCommandKeys = getDecoratedKeymaps();
const commandKeys = Object.keys(allCommandKeys).reduce((result, command) => {
const commandKeys = Object.keys(allCommandKeys).reduce((result: Record<string, string>, command) => {
result[command] = allCommandKeys[command][0];
return result;
}, {});
Expand All @@ -40,7 +43,7 @@ export const createMenu = (createWindow, getLoadedPluginVersions) => {
const pluginList =
loadedPlugins.length === 0 ? 'none' : loadedPlugins.map(plugin => `\n ${plugin.name} (${plugin.version})`);

const rendererCounts = Object.values(getRendererTypes()).reduce((acc, type) => {
const rendererCounts = Object.values(getRendererTypes()).reduce((acc: Record<string, number>, type) => {
acc[type] = acc[type] ? acc[type] + 1 : 1;
return acc;
}, {});
Expand All @@ -53,7 +56,7 @@ export const createMenu = (createWindow, getLoadedPluginVersions) => {
message: `${appName} ${appVersion} (${updateChannel})`,
detail: `Renderers: ${renderers}\nPlugins: ${pluginList}\n\nCreated by Guillermo Rauch\nCopyright © 2019 ZEIT, Inc.`,
buttons: [],
icon
icon: icon as any
});
};
const menu = [
Expand All @@ -69,7 +72,7 @@ export const createMenu = (createWindow, getLoadedPluginVersions) => {
return menu;
};

export const buildMenu = template => {
export const buildMenu = (template: Electron.MenuItemConstructorOptions[]): Electron.Menu => {
menu_ = Menu.buildFromTemplate(template);
return menu_;
};
15 changes: 9 additions & 6 deletions app/rpc.js → app/rpc.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {EventEmitter} from 'events';
import {ipcMain} from 'electron';
import {ipcMain, BrowserWindow} from 'electron';
import uuid from 'uuid';

class Server extends EventEmitter {
constructor(win) {
export class Server extends EventEmitter {
destroyed = false;
win: BrowserWindow;
id!: string;
constructor(win: BrowserWindow) {
super();
this.win = win;
this.ipcListener = this.ipcListener.bind(this);
Expand All @@ -29,11 +32,11 @@ class Server extends EventEmitter {
return this.win.webContents;
}

ipcListener(event, {ev, data}) {
ipcListener(event: any, {ev, data}: {ev: string; data: any}) {
super.emit(ev, data);
}

emit(ch, data) {
emit(ch: string, data: any): any {
// This check is needed because data-batching can cause extra data to be
// emitted after the window has already closed
if (!this.win.isDestroyed()) {
Expand All @@ -53,6 +56,6 @@ class Server extends EventEmitter {
}
}

export default win => {
export default (win: BrowserWindow) => {
return new Server(win);
};