Update state and reducer typings

This commit is contained in:
Labhansh Agrawal 2021-03-05 21:33:35 +05:30
parent 6199f1b025
commit aa9a50e8f9
8 changed files with 75 additions and 100 deletions

View file

@ -11,7 +11,6 @@ import findBySession from '../utils/term-groups';
import {getRootGroups} from '../selectors';
import {setActiveSession, ptyExitSession, userExitSession} from './sessions';
import {ITermState, ITermGroup, HyperState, HyperDispatch, HyperActions} from '../hyper';
import {Immutable} from 'seamless-immutable';
function requestSplit(direction: 'VERTICAL' | 'HORIZONTAL') {
return (activeUid: string) => (dispatch: HyperDispatch, getState: () => HyperState): void => {
@ -67,7 +66,7 @@ export function setActiveGroup(uid: string) {
// When we've found the next group which we want to
// set as active (after closing something), we also need
// to find the first child group which has a sessionUid.
const findFirstSession = (state: Immutable<ITermState>, group: Immutable<ITermGroup>): string | undefined => {
const findFirstSession = (state: ITermState, group: ITermGroup): string | undefined => {
if (group.sessionUid) {
return group.sessionUid;
}
@ -90,7 +89,7 @@ const findPrevious = <T>(list: T[], old: T) => {
return index ? list[index - 1] : list[1];
};
const findNextSessionUid = (state: Immutable<ITermState>, group: Immutable<ITermGroup>) => {
const findNextSessionUid = (state: ITermState, group: ITermGroup) => {
// If we're closing a root group (i.e. a whole tab),
// the next group needs to be a root group as well:
if (state.activeRootGroup === group.uid) {

View file

@ -28,7 +28,7 @@ import {
import {setActiveGroup} from './term-groups';
import parseUrl from 'parse-url';
import {HyperState, HyperDispatch, HyperActions} from '../hyper';
import {HyperState, HyperDispatch, HyperActions, ITermGroups} from '../hyper';
import {stat, Stats} from 'fs';
export function openContextMenu(uid: string, selection: any) {
@ -110,7 +110,7 @@ export function windowGeometryUpdated(): HyperActions {
// Find all sessions that are below the given
// termGroup uid in the hierarchy:
const findChildSessions = (termGroups: HyperState['termGroups']['termGroups'], uid: string): string[] => {
const findChildSessions = (termGroups: ITermGroups, uid: string): string[] => {
const group = termGroups[uid];
if (group.sessionUid) {
return [uid];

38
lib/config.d.ts vendored
View file

@ -1,5 +1,24 @@
import {FontWeight} from 'xterm';
export type ColorMap = {
black: string;
blue: string;
cyan: string;
green: string;
lightBlack: string;
lightBlue: string;
lightCyan: string;
lightGreen: string;
lightMagenta: string;
lightRed: string;
lightWhite: string;
lightYellow: string;
magenta: string;
red: string;
white: string;
yellow: string;
};
export type configOptions = {
autoUpdatePlugins: boolean | string;
backgroundColor: string;
@ -7,24 +26,7 @@ export type configOptions = {
bellSound: string | null;
bellSoundURL: string | null;
borderColor: string;
colors: {
black: string;
blue: string;
cyan: string;
green: string;
lightBlack: string;
lightBlue: string;
lightCyan: string;
lightGreen: string;
lightMagenta: string;
lightRed: string;
lightWhite: string;
lightYellow: string;
magenta: string;
red: string;
white: string;
yellow: string;
};
colors: ColorMap;
copyOnSelect: boolean;
css: string;
cursorAccentColor: string;

69
lib/hyper.d.ts vendored
View file

@ -9,27 +9,28 @@ declare global {
}
}
export type ITermGroup = {
export type ITermGroup = Immutable<{
uid: string;
sessionUid: string | null;
parentUid: string | null;
direction: 'HORIZONTAL' | 'VERTICAL' | null;
sizes: number[] | null;
children: string[];
};
}>;
export type ITermGroups = Record<string, ITermGroup>;
export type ITermGroups = Immutable<Record<string, ITermGroup>>;
export type ITermState = {
termGroups: ITermGroups;
export type ITermState = Immutable<{
termGroups: Mutable<ITermGroups>;
activeSessions: Record<string, string>;
activeRootGroup: string | null;
};
}>;
export type cursorShapes = 'BEAM' | 'UNDERLINE' | 'BLOCK';
import {FontWeight, Terminal} from 'xterm';
import {ColorMap} from './config';
export type uiState = {
export type uiState = Immutable<{
_lastUpdate: number | null;
activeUid: string | null;
activityMarkers: Record<string, boolean>;
@ -38,24 +39,7 @@ export type uiState = {
bellSoundURL: string | null;
bellSound: string | null;
borderColor: string;
colors: {
black: string;
blue: string;
cyan: string;
green: string;
lightBlack: string;
lightBlue: string;
lightCyan: string;
lightGreen: string;
lightMagenta: string;
lightRed: string;
lightWhite: string;
lightYellow: string;
magenta: string;
red: string;
white: string;
yellow: string;
};
colors: ColorMap;
cols: number | null;
copyOnSelect: boolean;
css: string;
@ -107,7 +91,7 @@ export type uiState = {
updateVersion: string | null;
webGLRenderer: boolean;
webLinksActivationKey: string;
};
}>;
export type session = {
cleared: boolean;
@ -123,22 +107,19 @@ export type session = {
splitDirection?: 'HORIZONTAL' | 'VERTICAL';
activeUid?: string;
};
export type sessionState = {
export type sessionState = Immutable<{
sessions: Record<string, session>;
activeUid: string | null;
write?: any;
};
}>;
export {ITermGroupReducer} from './reducers/term-groups';
import {ITermGroupReducer} from './reducers/term-groups';
export type ITermGroupReducer = Reducer<ITermState, HyperActions>;
export {IUiReducer} from './reducers/ui';
import {IUiReducer} from './reducers/ui';
export type IUiReducer = Reducer<uiState, HyperActions>;
export {ISessionReducer} from './reducers/sessions';
import {ISessionReducer} from './reducers/sessions';
export type ISessionReducer = Reducer<sessionState, HyperActions>;
import {Middleware} from 'redux';
import {Middleware, Reducer} from 'redux';
export type hyperPlugin = {
getTabProps: any;
getTabsProps: any;
@ -163,9 +144,9 @@ export type hyperPlugin = {
};
export type HyperState = {
ui: Immutable<uiState>;
sessions: Immutable<sessionState>;
termGroups: Immutable<ITermState>;
ui: uiState;
sessions: sessionState;
termGroups: ITermState;
};
import {UIActions} from './constants/ui';
@ -188,8 +169,6 @@ export type HyperActions = (
| TabActions
) & {effect?: () => void};
type immutableRecord<T> = {[k in keyof T]: Immutable<T[k]>};
import configureStore from './store/configure-store';
export type HyperDispatch = ReturnType<typeof configureStore>['dispatch'];
@ -276,7 +255,7 @@ export type TermGroupOwnProps = {
fontSmoothing?: string;
parentProps: TermsProps;
ref_: (uid: string, term: Term | null) => void;
termGroup: Immutable<ITermGroup>;
termGroup: ITermGroup;
terms: Record<string, Term | null>;
} & Pick<
TermsProps,
@ -336,7 +315,7 @@ export type TermProps = {
bellSoundURL: string | null;
borderColor: string;
cleared: boolean;
colors: uiState['colors'];
colors: ColorMap;
cols: number | null;
copyOnSelect: boolean;
cursorAccentColor?: string;
@ -379,4 +358,10 @@ export type TermProps = {
ref_: (uid: string, term: Term | null) => void;
} & extensionProps;
// Utility types
export type Mutable<T> = T extends Immutable<infer U> ? (Exclude<U, T> extends never ? U : Exclude<U, T>) : T;
export type immutableRecord<T> = {[k in keyof T]: Immutable<T[k]>};
export type Assignable<T, U> = {[k in keyof U]: k extends keyof T ? T[k] : U[k]} & Partial<T>;

View file

@ -1,4 +1,4 @@
import Immutable, {Immutable as ImmutableType} from 'seamless-immutable';
import Immutable from 'seamless-immutable';
import {decorateSessionsReducer} from '../utils/plugins';
import {
SESSION_ADD,
@ -13,10 +13,10 @@ import {
SESSION_SEARCH,
SESSION_SEARCH_CLOSE
} from '../constants/sessions';
import {sessionState, session, HyperActions} from '../hyper';
import {sessionState, session, Mutable, ISessionReducer} from '../hyper';
const initialState: ImmutableType<sessionState> = Immutable({
sessions: {} as Record<string, session>,
const initialState: sessionState = Immutable<Mutable<sessionState>>({
sessions: {},
activeUid: null
});
@ -35,7 +35,7 @@ function Session(obj: Immutable.DeepPartial<session>) {
return Immutable(x).merge(obj);
}
function deleteSession(state: ImmutableType<sessionState>, uid: string) {
function deleteSession(state: sessionState, uid: string) {
return state.updateIn(['sessions'], (sessions: typeof state['sessions']) => {
const sessions_ = sessions.asMutable();
delete sessions_[uid];
@ -43,7 +43,7 @@ function deleteSession(state: ImmutableType<sessionState>, uid: string) {
});
}
const reducer = (state: ImmutableType<sessionState> = initialState, action: HyperActions) => {
const reducer: ISessionReducer = (state = initialState, action) => {
switch (action.type) {
case SESSION_ADD:
return state.set('activeUid', action.uid).setIn(
@ -134,6 +134,4 @@ const reducer = (state: ImmutableType<sessionState> = initialState, action: Hype
}
};
export type ISessionReducer = typeof reducer;
export default decorateSessionsReducer(reducer);

View file

@ -4,17 +4,17 @@ import {TERM_GROUP_EXIT, TERM_GROUP_RESIZE} from '../constants/term-groups';
import {SESSION_ADD, SESSION_SET_ACTIVE, SessionAddAction} from '../constants/sessions';
import findBySession from '../utils/term-groups';
import {decorateTermGroupsReducer} from '../utils/plugins';
import {ITermGroup, ITermState, ITermGroups, HyperActions} from '../hyper';
import {ITermGroup, ITermState, ITermGroups, ITermGroupReducer, Mutable} from '../hyper';
const MIN_SIZE = 0.05;
const initialState = Immutable<ITermState>({
const initialState: ITermState = Immutable<Mutable<ITermState>>({
termGroups: {},
activeSessions: {},
activeRootGroup: null
});
function TermGroup(obj: Immutable.DeepPartial<ITermGroup>) {
const x: ITermGroup = {
function TermGroup(obj: Immutable.DeepPartial<Mutable<ITermGroup>>) {
const x: Mutable<ITermGroup> = {
uid: '',
sessionUid: null,
parentUid: null,
@ -26,7 +26,7 @@ function TermGroup(obj: Immutable.DeepPartial<ITermGroup>) {
}
// Recurse upwards until we find a root term group (no parent).
const findRootGroup = (termGroups: ImmutableType<ITermGroups>, uid: string): ImmutableType<ITermGroup> => {
const findRootGroup = (termGroups: ITermGroups, uid: string): ITermGroup => {
const current = termGroups[uid];
if (!current.parentUid) {
return current;
@ -35,7 +35,7 @@ const findRootGroup = (termGroups: ImmutableType<ITermGroups>, uid: string): Imm
return findRootGroup(termGroups, current.parentUid);
};
const setActiveGroup = (state: ImmutableType<ITermState>, action: {uid: string}) => {
const setActiveGroup = (state: ITermState, action: {uid: string}) => {
if (!action.uid) {
return state.set('activeRootGroup', null);
}
@ -66,7 +66,7 @@ const removalRebalance = (oldSizes: ImmutableType<number[]>, index: number) => {
);
};
const splitGroup = (state: ImmutableType<ITermState>, action: SessionAddAction) => {
const splitGroup = (state: ITermState, action: SessionAddAction) => {
const {splitDirection, uid, activeUid} = action;
const activeGroup = findBySession(state, activeUid!)!;
// If we're splitting in the same direction as the current active
@ -132,11 +132,7 @@ const splitGroup = (state: ImmutableType<ITermState>, action: SessionAddAction)
// Replace the parent by the given child in the tree,
// used when we remove another child and we're left
// with a one-to-one mapping between parent and child.
const replaceParent = (
state: ImmutableType<ITermState>,
parent: ImmutableType<ITermGroup>,
child: ImmutableType<ITermGroup>
) => {
const replaceParent = (state: ITermState, parent: ITermGroup, child: ITermGroup) => {
if (parent.parentUid) {
const parentParent = state.termGroups[parent.parentUid];
// If the parent we're replacing has a parent,
@ -161,7 +157,7 @@ const replaceParent = (
.setIn(['termGroups', child.uid, 'parentUid'], parent.parentUid);
};
const removeGroup = (state: ImmutableType<ITermState>, uid: string) => {
const removeGroup = (state: ITermState, uid: string) => {
const group = state.termGroups[uid];
// when close tab with multiple panes, it remove group from parent to child. so maybe the parentUid exists but parent group have removed.
// it's safe to remove the group.
@ -188,7 +184,7 @@ const removeGroup = (state: ImmutableType<ITermState>, uid: string) => {
.set('activeSessions', state.activeSessions.without(uid));
};
const resizeGroup = (state: ImmutableType<ITermState>, uid: string, sizes: number[]) => {
const resizeGroup = (state: ITermState, uid: string, sizes: number[]) => {
// Make sure none of the sizes fall below MIN_SIZE:
if (sizes.find((size) => size < MIN_SIZE)) {
return state;
@ -197,7 +193,7 @@ const resizeGroup = (state: ImmutableType<ITermState>, uid: string, sizes: numbe
return state.setIn(['termGroups', uid, 'sizes'], sizes);
};
const reducer = (state = initialState, action: HyperActions) => {
const reducer: ITermGroupReducer = (state = initialState, action) => {
switch (action.type) {
case SESSION_ADD: {
if (action.splitDirection) {
@ -227,6 +223,4 @@ const reducer = (state = initialState, action: HyperActions) => {
}
};
export type ITermGroupReducer = typeof reducer;
export default decorateTermGroupsReducer(reducer);

View file

@ -24,7 +24,7 @@ import {
SESSION_SET_CWD
} from '../constants/sessions';
import {UPDATE_AVAILABLE} from '../constants/updater';
import {uiState, HyperActions} from '../hyper';
import {uiState, Mutable, IUiReducer} from '../hyper';
const allowedCursorShapes = new Set(['BEAM', 'BLOCK', 'UNDERLINE']);
const allowedCursorBlinkValues = new Set([true, false]);
@ -33,7 +33,7 @@ const allowedHamburgerMenuValues = new Set([true, false]);
const allowedWindowControlsValues = new Set([true, false, 'left']);
// Populate `config-default.js` from this :)
const initial: ImmutableType<uiState> = Immutable({
const initial: uiState = Immutable<Mutable<uiState>>({
cols: null,
rows: null,
scrollback: 1000,
@ -57,7 +57,7 @@ const initial: ImmutableType<uiState> = Immutable({
letterSpacing: 0,
css: '',
termCSS: '',
openAt: {} as Record<string, number>,
openAt: {},
resizeAt: 0,
colors: {
black: '#000000',
@ -77,7 +77,7 @@ const initial: ImmutableType<uiState> = Immutable({
lightCyan: '#68FDFE',
lightWhite: '#FFFFFF'
},
activityMarkers: {} as Record<string, boolean>,
activityMarkers: {},
notifications: {
font: false,
resize: false,
@ -115,7 +115,7 @@ const initial: ImmutableType<uiState> = Immutable({
const currentWindow = remote.getCurrentWindow();
const reducer = (state = initial, action: HyperActions) => {
const reducer: IUiReducer = (state = initial, action) => {
let state_ = state;
let isMax;
switch (action.type) {
@ -127,7 +127,7 @@ const reducer = (state = initial, action: HyperActions) => {
// font size changed from the config
.merge(
(() => {
const ret: Immutable.DeepPartial<uiState> = {};
const ret: Immutable.DeepPartial<Mutable<uiState>> = {};
if (config.scrollback) {
ret.scrollback = config.scrollback;
@ -452,6 +452,4 @@ const reducer = (state = initial, action: HyperActions) => {
return state_;
};
export type IUiReducer = typeof reducer;
export default decorateUIReducer(reducer);

View file

@ -1,7 +1,6 @@
import {ITermState} from '../hyper';
import {Immutable} from 'seamless-immutable';
export default function findBySession(termGroupState: Immutable<ITermState>, sessionUid: string) {
export default function findBySession(termGroupState: ITermState, sessionUid: string) {
const {termGroups} = termGroupState;
return Object.keys(termGroups)
.map((uid) => termGroups[uid])