port js files in lib and lib/containers to ts (#3957)

* rename files in lib and lib/containers to ts

* add types

* fix ts errors
This commit is contained in:
Labhansh Agrawal 2019-11-11 20:51:42 +05:30 committed by Benjamin Staneck
parent d5d5bcc74c
commit a1eb84d8a7
17 changed files with 163 additions and 59 deletions

View file

@ -136,7 +136,7 @@ export function resizeSession(uid: string, cols: number, rows: number) {
};
}
export function onSearch(uid: string) {
export function onSearch(uid?: string) {
return (dispatch: Dispatch<any>, getState: () => HyperState) => {
const targetUid = uid || getState().sessions.activeUid;
dispatch({
@ -146,7 +146,7 @@ export function onSearch(uid: string) {
};
}
export function closeSearch(uid: string) {
export function closeSearch(uid?: string) {
return (dispatch: Dispatch<any>, getState: () => HyperState) => {
const targetUid = uid || getState().sessions.activeUid;
dispatch({
@ -156,7 +156,7 @@ export function closeSearch(uid: string) {
};
}
export function sendSessionData(uid: string, data: any, escaped: any) {
export function sendSessionData(uid: string | null, data: any, escaped?: any) {
return (dispatch: Dispatch<any>, getState: () => HyperState) => {
dispatch({
type: SESSION_USER_DATA,

View file

@ -170,7 +170,7 @@ export function moveLeft() {
type: UI_MOVE_LEFT,
effect() {
const state = getState();
const uid = state.termGroups.activeRootGroup;
const uid = state.termGroups.activeRootGroup!;
const groupUids = getGroupUids(state);
const index = groupUids.indexOf(uid);
const next = groupUids[index - 1] || groupUids[groupUids.length - 1];
@ -192,7 +192,7 @@ export function moveRight() {
effect() {
const state = getState();
const groupUids = getGroupUids(state);
const uid = state.termGroups.activeRootGroup;
const uid = state.termGroups.activeRootGroup!;
const index = groupUids.indexOf(uid);
const next = groupUids[index + 1] || groupUids[0];
if (!next || uid === next) {

View file

@ -3,21 +3,21 @@ import {remote} from 'electron';
const {getDecoratedKeymaps} = remote.require('./plugins');
let commands = {};
let commands: Record<string, any> = {};
export const getRegisteredKeys = () => {
const keymaps = getDecoratedKeymaps();
return Object.keys(keymaps).reduce((result, actionName) => {
return Object.keys(keymaps).reduce((result: Record<string, string>, actionName) => {
const commandKeys = keymaps[actionName];
commandKeys.forEach(shortcut => {
commandKeys.forEach((shortcut: string) => {
result[shortcut] = actionName;
});
return result;
}, {});
};
export const registerCommandHandlers = cmds => {
export const registerCommandHandlers = (cmds: typeof commands) => {
if (!cmds) {
return;
}
@ -25,7 +25,7 @@ export const registerCommandHandlers = cmds => {
commands = Object.assign(commands, cmds);
};
export const getCommandHandler = command => {
export const getCommandHandler = (command: string) => {
return commands[command];
};
@ -44,4 +44,4 @@ const roleCommands = [
'window:toggleFullScreen'
];
export const shouldPreventDefault = command => !roleCommands.includes(command);
export const shouldPreventDefault = (command: string) => !roleCommands.includes(command);

View file

@ -5,13 +5,15 @@ import Header from '../components/header';
import {closeTab, changeTab, maximize, openHamburgerMenu, unmaximize, minimize, close} from '../actions/header';
import {connect} from '../utils/plugins';
import getRootGroups from '../selectors';
import {HyperState} from '../hyper';
import {Dispatch} from 'redux';
const isMac = /Mac/.test(navigator.userAgent);
const getSessions = ({sessions}) => sessions.sessions;
const getActiveRootGroup = ({termGroups}) => termGroups.activeRootGroup;
const getActiveSessions = ({termGroups}) => termGroups.activeSessions;
const getActivityMarkers = ({ui}) => ui.activityMarkers;
const getSessions = ({sessions}: HyperState) => sessions.sessions;
const getActiveRootGroup = ({termGroups}: HyperState) => termGroups.activeRootGroup;
const getActiveSessions = ({termGroups}: HyperState) => termGroups.activeSessions;
const getActivityMarkers = ({ui}: HyperState) => ui.activityMarkers;
const getTabs = createSelector(
[getSessions, getRootGroups, getActiveSessions, getActiveRootGroup, getActivityMarkers],
(sessions, rootGroups, activeSessions, activeRootGroup, activityMarkers) =>
@ -28,7 +30,7 @@ const getTabs = createSelector(
);
const HeaderContainer = connect(
state => {
(state: HyperState) => {
return {
// active is an index
isMac,
@ -42,13 +44,13 @@ const HeaderContainer = connect(
showWindowControls: state.ui.showWindowControls
};
},
dispatch => {
(dispatch: Dispatch<any>) => {
return {
onCloseTab: i => {
onCloseTab: (i: string) => {
dispatch(closeTab(i));
},
onChangeTab: i => {
onChangeTab: (i: string) => {
dispatch(changeTab(i));
},
@ -60,7 +62,7 @@ const HeaderContainer = connect(
dispatch(unmaximize());
},
openHamburgerMenu: coordinates => {
openHamburgerMenu: (coordinates: {x: number; y: number}) => {
dispatch(openHamburgerMenu(coordinates));
},
@ -72,7 +74,8 @@ const HeaderContainer = connect(
dispatch(close());
}
};
}
},
null
)(Header, 'Header');
export default HeaderContainer;

View file

@ -11,22 +11,26 @@ import stylis from 'stylis';
import HeaderContainer from './header';
import TermsContainer from './terms';
import NotificationsContainer from './notifications';
import {HyperState} from '../hyper';
import {Dispatch} from 'redux';
const isMac = /Mac/.test(navigator.userAgent);
class Hyper extends React.PureComponent {
constructor(props) {
class Hyper extends React.PureComponent<any, any> {
mousetrap!: MousetrapInstance;
terms: any;
constructor(props: any) {
super(props);
this.handleFocusActive = this.handleFocusActive.bind(this);
this.handleSelectAll = this.handleSelectAll.bind(this);
this.onTermsRef = this.onTermsRef.bind(this);
this.mousetrap = null;
this.state = {
lastConfigUpdate: 0
};
}
//TODO: Remove usage of legacy and soon deprecated lifecycle methods
UNSAFE_componentWillReceiveProps(next) {
UNSAFE_componentWillReceiveProps(next: any) {
if (this.props.backgroundColor !== next.backgroundColor) {
// this can be removed when `setBackgroundColor` in electron
// starts working again
@ -39,7 +43,7 @@ class Hyper extends React.PureComponent {
}
}
handleFocusActive(uid) {
handleFocusActive(uid: string) {
const term = this.terms.getTermByUid(uid);
if (term) {
term.focus();
@ -55,7 +59,7 @@ class Hyper extends React.PureComponent {
attachKeyListeners() {
if (!this.mousetrap) {
this.mousetrap = new Mousetrap(window, true);
this.mousetrap = new Mousetrap();
this.mousetrap.stopCallback = () => {
// All events should be intercepted even if focus is in an input/textarea
return false;
@ -64,11 +68,11 @@ class Hyper extends React.PureComponent {
this.mousetrap.reset();
}
const keys = getRegisteredKeys();
const keys: Record<string, any> = getRegisteredKeys();
Object.keys(keys).forEach(commandKeys => {
this.mousetrap.bind(
commandKeys,
e => {
(e: any) => {
const command = keys[commandKeys];
// We should tell to xterm that it should ignore this event.
e.catched = true;
@ -85,12 +89,12 @@ class Hyper extends React.PureComponent {
window.rpc.on('term selectAll', this.handleSelectAll);
}
onTermsRef(terms) {
onTermsRef(terms: any) {
this.terms = terms;
window.focusActiveTerm = this.handleFocusActive;
}
componentDidUpdate(prev) {
componentDidUpdate(prev: any) {
if (prev.activeSession !== this.props.activeSession) {
this.handleFocusActive(this.props.activeSession);
}
@ -104,7 +108,7 @@ class Hyper extends React.PureComponent {
render() {
const {isMac: isMac_, customCSS, uiFontFamily, borderColor, maximized, fullScreen} = this.props;
const borderWidth = isMac_ ? '' : `${maximized ? '0' : '1'}px`;
stylis.set({prefix: false});
return (
<div id="hyper">
<div
@ -141,14 +145,14 @@ class Hyper extends React.PureComponent {
Add custom CSS to Hyper.
We add a scope to the customCSS so that it can get around the weighting applied by styled-jsx
*/}
<style dangerouslySetInnerHTML={{__html: stylis('#hyper', customCSS, {prefix: false})}} />
<style dangerouslySetInnerHTML={{__html: stylis('#hyper', customCSS)}} />
</div>
);
}
}
const HyperContainer = connect(
state => {
(state: HyperState) => {
return {
isMac,
customCSS: state.ui.css,
@ -161,9 +165,9 @@ const HyperContainer = connect(
lastConfigUpdate: state.ui._lastUpdate
};
},
dispatch => {
(dispatch: Dispatch<any>) => {
return {
execCommand: (command, fn, e) => {
execCommand: (command: any, fn: any, e: any) => {
dispatch(uiActions.execCommand(command, fn, e));
}
};

View file

@ -2,9 +2,11 @@ import Notifications from '../components/notifications';
import {installUpdate} from '../actions/updater';
import {connect} from '../utils/plugins';
import {dismissNotification} from '../actions/notifications';
import {HyperState} from '../hyper';
import {Dispatch} from 'redux';
const NotificationsContainer = connect(
state => {
(state: HyperState) => {
const {ui} = state;
const {notifications} = ui;
const state_ = {};
@ -34,7 +36,7 @@ const NotificationsContainer = connect(
Object.assign(state_, {
updateShowing: true,
updateVersion: ui.updateVersion,
updateNote: ui.updateNotes.split('\n')[0],
updateNote: ui.updateNotes!.split('\n')[0],
updateReleaseUrl: ui.updateReleaseUrl,
updateCanInstall: ui.updateCanInstall
});
@ -49,7 +51,7 @@ const NotificationsContainer = connect(
return state_;
},
dispatch => {
(dispatch: Dispatch<any>) => {
return {
onDismissFont: () => {
dispatch(dismissNotification('font'));
@ -67,7 +69,8 @@ const NotificationsContainer = connect(
dispatch(installUpdate());
}
};
}
},
null
)(Notifications, 'Notifications');
export default NotificationsContainer;

View file

@ -4,9 +4,11 @@ import {resizeSession, sendSessionData, setSessionXtermTitle, setActiveSession,
import {openContextMenu} from '../actions/ui';
import getRootGroups from '../selectors';
import {HyperState, TermsProps} from '../hyper';
import {Dispatch} from 'redux';
const TermsContainer = connect(
state => {
(state: HyperState): TermsProps => {
const {sessions} = state.sessions;
return {
sessions,
@ -47,28 +49,28 @@ const TermsContainer = connect(
disableLigatures: state.ui.disableLigatures
};
},
dispatch => {
(dispatch: Dispatch<any>) => {
return {
onData(uid, data) {
onData(uid: string, data: any) {
dispatch(sendSessionData(uid, data));
},
onTitle(uid, title) {
onTitle(uid: string, title: string) {
dispatch(setSessionXtermTitle(uid, title));
},
onResize(uid, cols, rows) {
onResize(uid: string, cols: number, rows: number) {
dispatch(resizeSession(uid, cols, rows));
},
onActive(uid) {
onActive(uid: string) {
dispatch(setActiveSession(uid));
},
toggleSearch(uid) {
toggleSearch(uid: string) {
dispatch(onSearch(uid));
},
onContextMenu(uid, selection) {
onContextMenu(uid: string, selection: any) {
dispatch(setActiveSession(uid));
dispatch(openContextMenu(uid, selection));
}

View file

@ -6,3 +6,7 @@ declare module 'php-escape-shell' {
declare module 'parse-url' {
export default function(...args: any[]): any;
}
declare module 'react-deep-force-update' {
export default function(...args: any[]): any;
}

55
lib/hyper.d.ts vendored
View file

@ -4,6 +4,8 @@ import {Immutable} from 'seamless-immutable';
declare global {
interface Window {
__rpcId: string;
rpc: any;
focusActiveTerm: any;
}
}
@ -29,7 +31,7 @@ export type ITermGroupReducer = Reducer<Immutable<ITermState>, any>;
export type uiState = {
_lastUpdate: null;
activeUid: string | null;
activityMarkers: {};
activityMarkers: Record<string, boolean>;
backgroundColor: string;
bell: string;
bellSoundURL: string | null;
@ -99,9 +101,9 @@ export type uiState = {
termCSS: string;
uiFontFamily: string;
updateCanInstall: null | boolean;
updateNotes: null;
updateReleaseUrl: null;
updateVersion: null;
updateNotes: string | null;
updateReleaseUrl: string | null;
updateVersion: string | null;
webGLRenderer: boolean;
};
@ -123,6 +125,7 @@ export type session = {
export type sessionState = {
sessions: Record<string, session>;
activeUid: string | null;
write?: any;
};
export type ISessionReducer = Reducer<Immutable<sessionState>>;
@ -151,3 +154,47 @@ export type hyperPlugin = {
import rootReducer from './reducers/index';
export type HyperState = ReturnType<typeof rootReducer>;
type immutableRecord<T> = {[k in keyof T]: Immutable<T[k]>};
export type TermsProps = {
activeRootGroup: string | null;
activeSession: string | null;
customCSS: string;
fontSmoothing: string;
termGroups: Immutable<ITermGroup>[];
} & immutableRecord<
Pick<
uiState,
| 'backgroundColor'
| 'bell'
| 'bellSound'
| 'bellSoundURL'
| 'borderColor'
| 'colors'
| 'cols'
| 'copyOnSelect'
| 'cursorAccentColor'
| 'cursorBlink'
| 'cursorColor'
| 'cursorShape'
| 'disableLigatures'
| 'fontFamily'
| 'fontSize'
| 'fontWeight'
| 'fontWeightBold'
| 'foregroundColor'
| 'letterSpacing'
| 'lineHeight'
| 'macOptionSelectionMode'
| 'modifierKeys'
| 'padding'
| 'quickEdit'
| 'rows'
| 'scrollback'
| 'selectionColor'
| 'uiFontFamily'
| 'webGLRenderer'
>
> &
immutableRecord<Pick<sessionState, 'sessions' | 'write'>>;

View file

@ -31,7 +31,7 @@ Object.defineProperty(window, 'rpc', {get: () => rpc});
Object.defineProperty(window, 'config', {get: () => config});
Object.defineProperty(window, 'plugins', {get: () => plugins});
const fetchFileData = configData => {
const fetchFileData = (configData: any) => {
const configInfo = Object.assign({}, configData, {bellSound: null});
if (!configInfo.bell || configInfo.bell.toUpperCase() !== 'SOUND' || !configInfo.bellSoundURL) {
store_.dispatch(reloadConfig(configInfo));

View file

@ -1,6 +1,7 @@
import {createSelector} from 'reselect';
import {HyperState} from './hyper';
const getTermGroups = ({termGroups}) => termGroups.termGroups;
const getTermGroups = ({termGroups}: Pick<HyperState, 'termGroups'>) => termGroups.termGroups;
const getRootGroups = createSelector(
getTermGroups,
termGroups =>

View file

@ -1,7 +1,7 @@
import {remote} from 'electron';
// TODO: Should be updates to new async API https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31
import {connect as reduxConnect} from 'react-redux';
import {connect as reduxConnect, Options} from 'react-redux';
import {basename} from 'path';
// patching Module._load
@ -11,7 +11,8 @@ import React, {PureComponent} from 'react';
import ReactDOM from 'react-dom';
import Notification from '../components/notification';
import notify from './notify';
import {hyperPlugin, IUiReducer, ISessionReducer, ITermGroupReducer} from '../hyper';
import {hyperPlugin, IUiReducer, ISessionReducer, ITermGroupReducer, HyperState} from '../hyper';
import {Dispatch} from 'redux';
// remote interface to `../plugins`
const plugins = remote.require('./plugins') as typeof import('../../app/plugins');
@ -426,9 +427,14 @@ export function getTabProps(tab: any, parentProps: any, props: any) {
// connects + decorates a class
// plugins can override mapToState, dispatchToProps
// and the class gets decorated (proxied)
export function connect(stateFn: Function, dispatchFn: Function, c: any, d = {}) {
export function connect<stateProps, dispatchProps>(
stateFn: (state: HyperState) => stateProps,
dispatchFn: (dispatch: Dispatch<any>) => dispatchProps,
c: any,
d: Options = {}
) {
return (Class: any, name: keyof typeof connectors) => {
return reduxConnect(
return reduxConnect<stateProps, dispatchProps, any, HyperState>(
state => {
let ret = stateFn(state);
connectors[name].state.forEach(fn => {

View file

@ -287,12 +287,15 @@
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
"@babel/preset-react": "7.6.3",
"@babel/preset-typescript": "7.6.0",
"@types/color": "3.0.0",
"@types/mousetrap": "^1.6.3",
"@types/node": "^12.12.7",
"@types/plist": "3.0.2",
"@types/react": "^16.9.11",
"@types/react-dom": "^16.9.4",
"@types/react-redux": "^7.1.5",
"@types/seamless-immutable": "7.1.11",
"@types/styled-jsx": "2.2.8",
"@types/uuid": "3.4.6",
"@typescript-eslint/eslint-plugin": "2.6.0",
"@typescript-eslint/parser": "2.6.0",

View file

@ -64,7 +64,7 @@ module.exports = [
extensions: ['.js', '.jsx', '.ts', '.tsx']
},
devtool: isProd ? 'hidden-source-map' : 'cheap-module-source-map',
entry: './lib/index.js',
entry: './lib/index.tsx',
output: {
path: path.join(__dirname, 'target', 'renderer'),
filename: 'bundle.js'

View file

@ -542,6 +542,25 @@
dependencies:
defer-to-connect "^1.0.1"
"@types/color-convert@*":
version "1.9.0"
resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-1.9.0.tgz#bfa8203e41e7c65471e9841d7e306a7cd8b5172d"
integrity sha512-OKGEfULrvSL2VRbkl/gnjjgbbF7ycIlpSsX7Nkab4MOWi5XxmgBYvuiQ7lcCFY5cPDz7MUNaKgxte2VRmtr4Fg==
dependencies:
"@types/color-name" "*"
"@types/color-name@*":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
"@types/color@3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.0.tgz#40f8a6bf2fd86e969876b339a837d8ff1b0a6e30"
integrity sha512-5qqtNia+m2I0/85+pd2YzAXaTyKO8j+svirO5aN+XaQJ5+eZ8nx0jPtEWZLxCi50xwYsX10xUHetFzfb1WEs4Q==
dependencies:
"@types/color-convert" "*"
"@types/debug@^4.1.4", "@types/debug@^4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
@ -584,6 +603,11 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/mousetrap@^1.6.3":
version "1.6.3"
resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.3.tgz#3159a01a2b21c9155a3d8f85588885d725dc987d"
integrity sha512-13gmo3M2qVvjQrWNseqM3+cR6S2Ss3grbR2NZltgMq94wOwqJYQdgn8qzwDshzgXqMlSUtyPZjysImmktu22ew==
"@types/node@*", "@types/node@^12.0.12", "@types/node@^12.12.7":
version "12.12.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.7.tgz#01e4ea724d9e3bd50d90c11fd5980ba317d8fa11"
@ -637,6 +661,13 @@
resolved "https://registry.yarnpkg.com/@types/seamless-immutable/-/seamless-immutable-7.1.11.tgz#89250c3e2587a44c2a051f5798e6f29f0e91bbc9"
integrity sha512-U8Mp+Q6P5ZxG6KDRwWduQl822MnsnBtOq/Lb4HQB9Tzi8t1nr7PLqq88I4kTwEDHO95hcH8y8KhGvxWPIS6QoQ==
"@types/styled-jsx@2.2.8":
version "2.2.8"
resolved "https://registry.yarnpkg.com/@types/styled-jsx/-/styled-jsx-2.2.8.tgz#b50d13d8a3c34036282d65194554cf186bab7234"
integrity sha512-Yjye9VwMdYeXfS71ihueWRSxrruuXTwKCbzue4+5b2rjnQ//AtyM7myZ1BEhNhBQ/nL/RE7bdToUoLln2miKvg==
dependencies:
"@types/react" "*"
"@types/uuid@3.4.6":
version "3.4.6"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.6.tgz#d2c4c48eb85a757bf2927f75f939942d521e3016"