1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-23 18:53:36 +02:00

Chore: Refactor EventManager to use stronger types (#10272)

This commit is contained in:
Henry Heino 2024-04-06 10:08:16 -07:00 committed by GitHub
parent 9713034f18
commit 58ca1a938b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 79 additions and 67 deletions

View File

@ -125,8 +125,7 @@ function NoteEditor(props: NoteEditorProps) {
return async function() { return async function() {
const note = await formNoteToNote(formNote); const note = await formNoteToNote(formNote);
reg.logger().debug('Saving note...', note); reg.logger().debug('Saving note...', note);
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied const savedNote = await Note.save(note);
const savedNote: any = await Note.save(note);
setFormNote((prev: FormNote) => { setFormNote((prev: FormNote) => {
return { ...prev, user_updated_time: savedNote.user_updated_time, hasChanged: false }; return { ...prev, user_updated_time: savedNote.user_updated_time, hasChanged: false };

View File

@ -1,6 +1,6 @@
const fastDeepEqual = require('fast-deep-equal'); const fastDeepEqual = require('fast-deep-equal');
import { EventEmitter } from 'events';
const events = require('events'); import type { State as AppState } from './reducer';
export enum EventName { export enum EventName {
ResourceCreate = 'resourceCreate', ResourceCreate = 'resourceCreate',
@ -20,30 +20,34 @@ export enum EventName {
NoteResourceIndexed = 'noteResourceIndexed', NoteResourceIndexed = 'noteResourceIndexed',
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of old code from before rule was applied
export type EventListenerCallback = (...args: any[])=> void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of old code from before rule was applied
type AppStateChangeCallback = (event: { value: any })=> void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of old code from before rule was applied
type FilterObject = any;
export type FilterHandler = (object: FilterObject)=> FilterObject;
export class EventManager { export class EventManager {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied private emitter_: EventEmitter;
private emitter_: any; private appStatePrevious_: Record<string, AppState[keyof AppState]>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
private appStatePrevious_: any;
private appStateWatchedProps_: string[]; private appStateWatchedProps_: string[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied private appStateListeners_: Record<string, AppStateChangeCallback[]>;
private appStateListeners_: any;
public constructor() { public constructor() {
this.reset(); this.reset();
} }
public reset() { public reset() {
this.emitter_ = new events.EventEmitter(); this.emitter_ = new EventEmitter();
this.appStatePrevious_ = {}; this.appStatePrevious_ = {};
this.appStateWatchedProps_ = []; this.appStateWatchedProps_ = [];
this.appStateListeners_ = {}; this.appStateListeners_ = {};
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public on(eventName: EventName, callback: EventListenerCallback) {
public on(eventName: EventName, callback: Function) {
return this.emitter_.on(eventName, callback); return this.emitter_.on(eventName, callback);
} }
@ -52,23 +56,19 @@ export class EventManager {
return this.emitter_.emit(eventName, object); return this.emitter_.emit(eventName, object);
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public removeListener(eventName: string, callback: EventListenerCallback) {
public removeListener(eventName: string, callback: Function) {
return this.emitter_.removeListener(eventName, callback); return this.emitter_.removeListener(eventName, callback);
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public off(eventName: EventName, callback: EventListenerCallback) {
public off(eventName: EventName, callback: Function) {
return this.removeListener(eventName, callback); return this.removeListener(eventName, callback);
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public filterOn(filterName: string, callback: FilterHandler) {
public filterOn(filterName: string, callback: Function) {
return this.emitter_.on(`filter:${filterName}`, callback); return this.emitter_.on(`filter:${filterName}`, callback);
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public filterOff(filterName: string, callback: FilterHandler) {
public filterOff(filterName: string, callback: Function) {
return this.removeListener(`filter:${filterName}`, callback); return this.removeListener(`filter:${filterName}`, callback);
} }
@ -95,8 +95,7 @@ export class EventManager {
return output; return output;
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public appStateOn(propName: string, callback: AppStateChangeCallback) {
public appStateOn(propName: string, callback: Function) {
if (!this.appStateListeners_[propName]) { if (!this.appStateListeners_[propName]) {
this.appStateListeners_[propName] = []; this.appStateListeners_[propName] = [];
this.appStateWatchedProps_.push(propName); this.appStateWatchedProps_.push(propName);
@ -105,8 +104,7 @@ export class EventManager {
this.appStateListeners_[propName].push(callback); this.appStateListeners_[propName].push(callback);
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public appStateOff(propName: string, callback: AppStateChangeCallback) {
public appStateOff(propName: string, callback: Function) {
if (!this.appStateListeners_[propName]) { if (!this.appStateListeners_[propName]) {
throw new Error('EventManager: Trying to unregister a state prop watch for a non-watched prop (1)'); throw new Error('EventManager: Trying to unregister a state prop watch for a non-watched prop (1)');
} }
@ -117,10 +115,10 @@ export class EventManager {
this.appStateListeners_[propName].splice(idx, 1); this.appStateListeners_[propName].splice(idx, 1);
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied private stateValue_(state: AppState, propName: string) {
private stateValue_(state: any, propName: string) {
const parts = propName.split('.'); const parts = propName.split('.');
let s = state; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partially refactored old code from before rule was applied.
let s: any = state;
for (const p of parts) { for (const p of parts) {
if (!(p in s)) throw new Error(`Invalid state property path: ${propName}`); if (!(p in s)) throw new Error(`Invalid state property path: ${propName}`);
s = s[p]; s = s[p];
@ -131,8 +129,7 @@ export class EventManager {
// This function works by keeping a copy of the watched props and, whenever this function // This function works by keeping a copy of the watched props and, whenever this function
// is called, comparing the previous and new values and emitting events if they have changed. // is called, comparing the previous and new values and emitting events if they have changed.
// The appStateEmit function should be called from a middleware. // The appStateEmit function should be called from a middleware.
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public appStateEmit(state: AppState) {
public appStateEmit(state: any) {
if (!this.appStateWatchedProps_.length) return; if (!this.appStateWatchedProps_.length) return;
for (const propName of this.appStateWatchedProps_) { for (const propName of this.appStateWatchedProps_) {
@ -157,8 +154,7 @@ export class EventManager {
} }
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public once(eventName: string, callback: EventListenerCallback) {
public once(eventName: string, callback: any) {
return this.emitter_.once(eventName, callback); return this.emitter_.once(eventName, callback);
} }

View File

@ -1,5 +1,5 @@
import { State } from '../reducer'; import { State } from '../reducer';
import eventManager, { EventName } from '../eventManager'; import eventManager, { EventListenerCallback, EventName } from '../eventManager';
import BaseService from './BaseService'; import BaseService from './BaseService';
import shim from '../shim'; import shim from '../shim';
import WhenClause from './WhenClause'; import WhenClause from './WhenClause';
@ -57,6 +57,16 @@ export interface Command {
runtime?: CommandRuntime; runtime?: CommandRuntime;
} }
interface CommandSpec {
declaration: CommandDeclaration;
runtime: ()=> CommandRuntime;
}
interface ComponentCommandSpec<ComponentType> {
declaration: CommandDeclaration;
runtime: (component: ComponentType)=> CommandRuntime;
}
interface Commands { interface Commands {
[key: string]: Command; [key: string]: Command;
} }
@ -114,13 +124,11 @@ export default class CommandService extends BaseService {
this.stateToWhenClauseContext_ = stateToWhenClauseContext; this.stateToWhenClauseContext_ = stateToWhenClauseContext;
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public on(eventName: EventName, callback: EventListenerCallback) {
public on(eventName: EventName, callback: Function) {
eventManager.on(eventName, callback); eventManager.on(eventName, callback);
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public off(eventName: EventName, callback: EventListenerCallback) {
public off(eventName: EventName, callback: Function) {
eventManager.off(eventName, callback); eventManager.off(eventName, callback);
} }
@ -204,29 +212,26 @@ export default class CommandService extends BaseService {
command.runtime = runtime; command.runtime = runtime;
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public registerCommands(commands: CommandSpec[]) {
public registerCommands(commands: any[]) {
for (const command of commands) { for (const command of commands) {
CommandService.instance().registerRuntime(command.declaration.name, command.runtime()); CommandService.instance().registerRuntime(command.declaration.name, command.runtime());
} }
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public unregisterCommands(commands: CommandSpec[]) {
public unregisterCommands(commands: any[]) {
for (const command of commands) { for (const command of commands) {
CommandService.instance().unregisterRuntime(command.declaration.name); CommandService.instance().unregisterRuntime(command.declaration.name);
} }
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public componentRegisterCommands<ComponentType>(component: ComponentType, commands: ComponentCommandSpec<ComponentType>[]) {
public componentRegisterCommands(component: any, commands: any[]) {
for (const command of commands) { for (const command of commands) {
CommandService.instance().registerRuntime(command.declaration.name, command.runtime(component)); CommandService.instance().registerRuntime(command.declaration.name, command.runtime(component));
} }
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public componentUnregisterCommands(commands: any[]) { public componentUnregisterCommands(commands: ComponentCommandSpec<any>[]) {
for (const command of commands) { for (const command of commands) {
CommandService.instance().unregisterRuntime(command.declaration.name); CommandService.instance().unregisterRuntime(command.declaration.name);
} }

View File

@ -1,4 +1,4 @@
import eventManager, { EventName } from '../eventManager'; import eventManager, { EventListenerCallback, EventName } from '../eventManager';
import shim from '../shim'; import shim from '../shim';
import { _ } from '../locale'; import { _ } from '../locale';
import keysRegExp from './KeymapService_keysRegExp'; import keysRegExp from './KeymapService_keysRegExp';
@ -415,13 +415,11 @@ export default class KeymapService extends BaseService {
return parts.join('+'); return parts.join('+');
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public on(eventName: EventName, callback: EventListenerCallback) {
public on(eventName: EventName, callback: Function) {
eventManager.on(eventName, callback); eventManager.on(eventName, callback);
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public off(eventName: EventName, callback: EventListenerCallback) {
public off(eventName: EventName, callback: Function) {
eventManager.off(eventName, callback); eventManager.off(eventName, callback);
} }

View File

@ -1,6 +1,7 @@
/* eslint-disable multiline-comment-style */ /* eslint-disable multiline-comment-style */
import eventManager from '../../../eventManager'; import eventManager, { FilterHandler } from '../../../eventManager';
/** /**
* @ignore * @ignore
@ -9,13 +10,11 @@ import eventManager from '../../../eventManager';
* so for now disable filters. * so for now disable filters.
*/ */
export default class JoplinFilters { export default class JoplinFilters {
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public async on(name: string, callback: FilterHandler) {
public async on(name: string, callback: Function) {
eventManager.filterOn(name, callback); eventManager.filterOn(name, callback);
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public async off(name: string, callback: FilterHandler) {
public async off(name: string, callback: Function) {
eventManager.filterOff(name, callback); eventManager.filterOff(name, callback);
} }
} }

View File

@ -44,9 +44,28 @@ interface ResourceChangeEvent {
id: string; id: string;
} }
type ItemChangeHandler = (event: ItemChangeEvent)=> void; interface NoteContentChangeEvent {
type SyncStartHandler = (event: SyncStartEvent)=> void; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- No plugin-api-accessible Note type defined.
type ResourceChangeHandler = (event: ResourceChangeEvent)=> void; note: any;
}
interface NoteSelectionChangeEvent {
value: string[];
}
interface NoteAlarmTriggerEvent {
noteId: string;
}
interface SyncCompleteEvent {
withErrors: boolean;
}
type WorkspaceEventHandler<EventType> = (event: EventType)=> void;
type ItemChangeHandler = WorkspaceEventHandler<ItemChangeEvent>;
type SyncStartHandler = WorkspaceEventHandler<SyncStartEvent>;
type ResourceChangeHandler = WorkspaceEventHandler<ResourceChangeEvent>;
/** /**
* The workspace service provides access to all the parts of Joplin that * The workspace service provides access to all the parts of Joplin that
@ -71,7 +90,7 @@ export default class JoplinWorkspace {
* Called when a new note or notes are selected. * Called when a new note or notes are selected.
*/ */
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
public async onNoteSelectionChange(callback: Function): Promise<Disposable> { public async onNoteSelectionChange(callback: WorkspaceEventHandler<NoteSelectionChangeEvent>): Promise<Disposable> {
eventManager.appStateOn('selectedNoteIds', callback); eventManager.appStateOn('selectedNoteIds', callback);
return {}; return {};
@ -87,8 +106,7 @@ export default class JoplinWorkspace {
* Called when the content of a note changes. * Called when the content of a note changes.
* @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes. * @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes.
*/ */
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public async onNoteContentChange(callback: WorkspaceEventHandler<NoteContentChangeEvent>) {
public async onNoteContentChange(callback: Function) {
eventManager.on(EventName.NoteContentChange, callback); eventManager.on(EventName.NoteContentChange, callback);
} }
@ -121,8 +139,7 @@ export default class JoplinWorkspace {
/** /**
* Called when an alarm associated with a to-do is triggered. * Called when an alarm associated with a to-do is triggered.
*/ */
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public async onNoteAlarmTrigger(handler: WorkspaceEventHandler<NoteAlarmTriggerEvent>): Promise<Disposable> {
public async onNoteAlarmTrigger(handler: Function): Promise<Disposable> {
return makeListener(eventManager, EventName.NoteAlarmTrigger, handler); return makeListener(eventManager, EventName.NoteAlarmTrigger, handler);
} }
@ -136,8 +153,7 @@ export default class JoplinWorkspace {
/** /**
* Called when the synchronisation process has finished. * Called when the synchronisation process has finished.
*/ */
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public async onSyncComplete(callback: WorkspaceEventHandler<SyncCompleteEvent>): Promise<Disposable> {
public async onSyncComplete(callback: Function): Promise<Disposable> {
return makeListener(eventManager, EventName.SyncComplete, callback); return makeListener(eventManager, EventName.SyncComplete, callback);
} }

View File

@ -1,8 +1,7 @@
import { EventManager, EventName } from '../../../eventManager'; import { EventListenerCallback, EventManager, EventName } from '../../../eventManager';
import { Disposable } from '../api/types'; import { Disposable } from '../api/types';
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied export default function(eventManager: EventManager, eventName: EventName, callback: EventListenerCallback): Disposable {
export default function(eventManager: EventManager, eventName: EventName, callback: Function): Disposable {
eventManager.on(eventName, callback); eventManager.on(eventName, callback);
return {}; return {};