diff --git a/frontend/obsidian-plugin/src/vault-link-plugin.ts b/frontend/obsidian-plugin/src/vault-link-plugin.ts index 50048e83..0d4c1a1d 100644 --- a/frontend/obsidian-plugin/src/vault-link-plugin.ts +++ b/frontend/obsidian-plugin/src/vault-link-plugin.ts @@ -120,7 +120,7 @@ export default class VaultLinkPlugin extends Plugin { this.app.workspace.onLayoutReady(async () => { this.registerEditorEvents(); - void this.client.start(); + await this.client.start(); const interval = setInterval(() => { updateEditorStatusDisplay(this.app.workspace, this.client); diff --git a/frontend/obsidian-plugin/src/views/cursors/update-selection.ts b/frontend/obsidian-plugin/src/views/cursors/update-selection.ts index 2551f863..9ff7c207 100644 --- a/frontend/obsidian-plugin/src/views/cursors/update-selection.ts +++ b/frontend/obsidian-plugin/src/views/cursors/update-selection.ts @@ -14,7 +14,7 @@ export const updateSelection = ({ }): void => { spans.forEach((span) => { if (fromA <= span.start) { - // The change covers the entirety of the selection + // the change covers the entirety of the selection if (toA > span.end) { span.start = toB; span.end = toB; @@ -23,6 +23,8 @@ export const updateSelection = ({ let change = toB - toA; if (change < 0) { + // it's a deletion + // if overlaps with the start, we can't move it back more than the deleted range change = Math.max(change, fromA - span.start); } @@ -31,6 +33,7 @@ export const updateSelection = ({ } else if (toA <= span.end) { span.end += toB - toA; } else if (toB <= span.end) { + // a deletion overlaps with the end, so we move the end span.end = toB; } }); diff --git a/frontend/obsidian-plugin/src/views/history/history-view.ts b/frontend/obsidian-plugin/src/views/history/history-view.ts index 68681f3e..631fde72 100644 --- a/frontend/obsidian-plugin/src/views/history/history-view.ts +++ b/frontend/obsidian-plugin/src/views/history/history-view.ts @@ -24,13 +24,12 @@ export class HistoryView extends ItemView { super(leaf); this.icon = HistoryView.ICON; - this.client.addSyncHistoryUpdateListener( - () => - void this.updateView().catch((error: unknown) => { - this.client.logger.error( - `Failed to update history view: ${error}` - ); - }) + this.client.addSyncHistoryUpdateListener(async () => + this.updateView().catch((error: unknown) => { + this.client.logger.error( + `Failed to update history view: ${error}` + ); + }) ); } @@ -109,7 +108,15 @@ export class HistoryView extends ItemView { this.historyContainer = container.createDiv({ cls: "logs-container" }); await this.updateView(); - this.timer = setInterval(() => void this.updateView(), 1000); + this.timer = setInterval( + () => + void this.updateView().catch((error: unknown) => { + this.client.logger.error( + `Failed to update history view: ${error}` + ); + }), + 1000 + ); } public async onClose(): Promise { @@ -174,11 +181,17 @@ export class HistoryView extends ItemView { null ) { card.addEventListener("click", () => { - void this.app.workspace.openLinkText( - entry.details.relativePath, - entry.details.relativePath, - false - ); + this.app.workspace + .openLinkText( + entry.details.relativePath, + entry.details.relativePath, + false + ) + .catch((error: unknown) => { + this.client.logger.error( + `Failed to open link for ${entry.details.relativePath}: ${error}` + ); + }); }); card.addClass("clickable"); diff --git a/frontend/obsidian-plugin/src/views/settings/settings-tab.ts b/frontend/obsidian-plugin/src/views/settings/settings-tab.ts index 34d1760a..2d129edc 100644 --- a/frontend/obsidian-plugin/src/views/settings/settings-tab.ts +++ b/frontend/obsidian-plugin/src/views/settings/settings-tab.ts @@ -16,7 +16,7 @@ export class SyncSettingsTab extends PluginSettingTab { private readonly plugin: VaultLinkPlugin; private readonly syncClient: SyncClient; private readonly statusDescription: StatusDescription; - private statusDescriptionSubscription: (() => void) | undefined; + private statusDescriptionSubscription: (() => unknown) | undefined; public constructor({ app, @@ -90,11 +90,12 @@ export class SyncSettingsTab extends PluginSettingTab { cls: "description" }, (descriptionContainer) => { - this.setStatusDescriptionSubscription((): void => { - this.statusDescription.renderStatusDescription( + this.setStatusDescriptionSubscription( + this.statusDescription.renderStatusDescription.bind( + this.statusDescription, descriptionContainer - ); - }); + ) + ); } ); @@ -339,7 +340,7 @@ export class SyncSettingsTab extends PluginSettingTab { } private setStatusDescriptionSubscription( - newSubscription?: () => void + newSubscription?: () => unknown ): void { if (this.statusDescriptionSubscription) { this.statusDescription.removeStatusChangeListener( @@ -360,7 +361,7 @@ export class SyncSettingsTab extends PluginSettingTab { settingName: keyof SyncSettings ): [ DocumentFragment, - (newValue: SyncSettings[keyof SyncSettings]) => void + (newValue: SyncSettings[keyof SyncSettings]) => unknown ] { const titleContainer = document.createDocumentFragment(); const title = titleContainer.createEl("div", { diff --git a/frontend/obsidian-plugin/src/views/status-bar/status-bar.ts b/frontend/obsidian-plugin/src/views/status-bar/status-bar.ts index 6289b0ca..6466601c 100644 --- a/frontend/obsidian-plugin/src/views/status-bar/status-bar.ts +++ b/frontend/obsidian-plugin/src/views/status-bar/status-bar.ts @@ -42,9 +42,7 @@ export class StatusBar { text: "VaultLink is disabled, click to configure", cls: "initialize-button" }); - button.onclick = (): void => { - this.plugin.openSettings(); - }; + button.onclick = this.plugin.openSettings.bind(this.plugin); return; } diff --git a/frontend/obsidian-plugin/src/views/status-description/status-description.ts b/frontend/obsidian-plugin/src/views/status-description/status-description.ts index 3bf41759..666c107b 100644 --- a/frontend/obsidian-plugin/src/views/status-description/status-description.ts +++ b/frontend/obsidian-plugin/src/views/status-description/status-description.ts @@ -28,12 +28,12 @@ export class StatusDescription { } ); - this.syncClient.addWebSocketStatusChangeListener( - () => void this.updateConnectionState() + this.syncClient.addWebSocketStatusChangeListener(async () => + this.updateConnectionState() ); - this.syncClient.addOnSettingsChangeListener( - () => void this.updateConnectionState() + this.syncClient.addOnSettingsChangeListener(async () => + this.updateConnectionState() ); } @@ -42,10 +42,10 @@ export class StatusDescription { this.updateDescription(); } - public addStatusChangeListener(listener: () => void): void { + public addStatusChangeListener(listener: () => unknown): void { this.statusChangeListeners.push(listener); } - public removeStatusChangeListener(listener: () => void): void { + public removeStatusChangeListener(listener: () => unknown): void { this.statusChangeListeners = this.statusChangeListeners.filter( (l) => l !== listener ); diff --git a/frontend/sync-client/src/persistence/database.ts b/frontend/sync-client/src/persistence/database.ts index 824ac6e7..0abefd4f 100644 --- a/frontend/sync-client/src/persistence/database.ts +++ b/frontend/sync-client/src/persistence/database.ts @@ -331,6 +331,8 @@ export class Database { ), lastSeenUpdateId: this.lastSeenUpdateIds.min, hasInitialSyncCompleted: this.hasInitialSyncCompleted + }).catch((error: unknown) => { + this.logger.error(`Error saving data: ${error}`); }); } diff --git a/frontend/sync-client/src/persistence/settings.ts b/frontend/sync-client/src/persistence/settings.ts index bcb32531..b0aff937 100644 --- a/frontend/sync-client/src/persistence/settings.ts +++ b/frontend/sync-client/src/persistence/settings.ts @@ -28,7 +28,7 @@ export class Settings { private readonly onSettingsChangeHandlers: (( newSettings: SyncSettings, oldSettings: SyncSettings - ) => void)[] = []; + ) => unknown)[] = []; public constructor( private readonly logger: Logger, @@ -50,7 +50,7 @@ export class Settings { } public addOnSettingsChangeListener( - handler: (settings: SyncSettings, oldSettings: SyncSettings) => void + handler: (settings: SyncSettings, oldSettings: SyncSettings) => unknown ): void { this.onSettingsChangeHandlers.push(handler); } diff --git a/frontend/sync-client/src/services/connection-status.ts b/frontend/sync-client/src/services/connection-status.ts index 3934639f..18f53a0d 100644 --- a/frontend/sync-client/src/services/connection-status.ts +++ b/frontend/sync-client/src/services/connection-status.ts @@ -7,8 +7,8 @@ export class ConnectionStatus { private static readonly UNTIL_RESOLUTION = Symbol(); private canFetch: boolean; private until: Promise; - private resolveUntil: (result: symbol) => void; - private rejectUntil: (reason: unknown) => void; + private resolveUntil: (result: symbol) => unknown; + private rejectUntil: (reason: unknown) => unknown; public constructor( settings: Settings, diff --git a/frontend/sync-client/src/services/websocket-manager.ts b/frontend/sync-client/src/services/websocket-manager.ts index 285d51f9..3a5b32b4 100644 --- a/frontend/sync-client/src/services/websocket-manager.ts +++ b/frontend/sync-client/src/services/websocket-manager.ts @@ -64,12 +64,12 @@ export class WebSocketManager { ); } - public addWebSocketStatusChangeListener(listener: () => void): void { + public addWebSocketStatusChangeListener(listener: () => unknown): void { this.webSocketStatusChangeListeners.push(listener); } public addRemoteCursorsUpdateListener( - listener: (cursors: ClientCursors[]) => void + listener: (cursors: ClientCursors[]) => unknown ): void { this.remoteCursorsUpdateListeners.push(listener); } diff --git a/frontend/sync-client/src/sync-client.ts b/frontend/sync-client/src/sync-client.ts index 972d2cd3..c7f0ea1b 100644 --- a/frontend/sync-client/src/sync-client.ts +++ b/frontend/sync-client/src/sync-client.ts @@ -48,9 +48,9 @@ export class SyncClient { private readonly fileOperations: FileOperations ) { this.settings.addOnSettingsChangeListener( - (newSettings, oldSettings) => { + async (newSettings, oldSettings) => { if (newSettings.vaultName !== oldSettings.vaultName) { - void this.reset(); + await this.reset(); } } ); @@ -197,7 +197,7 @@ export class SyncClient { } public addSyncHistoryUpdateListener( - listener: (stats: HistoryStats) => void + listener: (stats: HistoryStats) => unknown ): void { this.history.addSyncHistoryUpdateListener(listener); } @@ -227,7 +227,7 @@ export class SyncClient { this.database.reset(); this._logger.reset(); this.connectionStatus.finishReset(); - void this.start(); + await this.start(); } public getSettings(): SyncSettings { @@ -246,18 +246,18 @@ export class SyncClient { } public addOnSettingsChangeListener( - handler: (settings: SyncSettings, oldSettings: SyncSettings) => void + handler: (settings: SyncSettings, oldSettings: SyncSettings) => unknown ): void { this.settings.addOnSettingsChangeListener(handler); } public addRemainingSyncOperationsListener( - listener: (remainingOperations: number) => void + listener: (remainingOperations: number) => unknown ): void { this.syncer.addRemainingOperationsListener(listener); } - public addWebSocketStatusChangeListener(listener: () => void): void { + public addWebSocketStatusChangeListener(listener: () => unknown): void { this.webSocketManager.addWebSocketStatusChangeListener(listener); } @@ -344,7 +344,7 @@ export class SyncClient { } public addRemoteCursorsUpdateListener( - listener: (cursors: DocumentWithMaybeOutdatedClientCursors[]) => void + listener: (cursors: DocumentWithMaybeOutdatedClientCursors[]) => unknown ): void { this.webSocketManager.addRemoteCursorsUpdateListener(async () => { listener(await this.getRelevantClientCursors()); diff --git a/frontend/sync-client/src/sync-operations/syncer.ts b/frontend/sync-client/src/sync-operations/syncer.ts index 30e012d9..7e9301a5 100644 --- a/frontend/sync-client/src/sync-operations/syncer.ts +++ b/frontend/sync-client/src/sync-operations/syncer.ts @@ -22,7 +22,7 @@ export class Syncer { private readonly remoteDocumentsLock: Locks; private readonly remainingOperationsListeners: (( remainingOperations: number - ) => void)[] = []; + ) => unknown)[] = []; private readonly syncQueue: PQueue; private runningScheduleSyncForOfflineChanges: Promise | undefined; @@ -57,7 +57,7 @@ export class Syncer { } public addRemainingOperationsListener( - listener: (remainingOperations: number) => void + listener: (remainingOperations: number) => unknown ): void { this.remainingOperationsListeners.push(listener); } diff --git a/frontend/sync-client/src/tracing/logger.ts b/frontend/sync-client/src/tracing/logger.ts index dc259320..cf39e4de 100644 --- a/frontend/sync-client/src/tracing/logger.ts +++ b/frontend/sync-client/src/tracing/logger.ts @@ -23,9 +23,11 @@ export class LogLine { export class Logger { private static readonly MAX_MESSAGES = 100000; private readonly messages: LogLine[] = []; - private readonly onMessageListeners: ((message: LogLine) => void)[] = []; + private readonly onMessageListeners: ((message: LogLine) => unknown)[] = []; - public constructor(...onMessageListeners: ((message: LogLine) => void)[]) { + public constructor( + ...onMessageListeners: ((message: LogLine) => unknown)[] + ) { this.onMessageListeners = onMessageListeners; } @@ -53,7 +55,7 @@ export class Logger { ); } - public addOnMessageListener(listener: (message: LogLine) => void): void { + public addOnMessageListener(listener: (message: LogLine) => unknown): void { this.onMessageListeners.push(listener); } diff --git a/frontend/sync-client/src/tracing/sync-history.ts b/frontend/sync-client/src/tracing/sync-history.ts index 4cc5e77e..6890688b 100644 --- a/frontend/sync-client/src/tracing/sync-history.ts +++ b/frontend/sync-client/src/tracing/sync-history.ts @@ -70,7 +70,7 @@ export class SyncHistory { private readonly syncHistoryUpdateListeners: (( status: HistoryStats - ) => void)[] = []; + ) => unknown)[] = []; private status: HistoryStats = { success: 0, @@ -111,7 +111,7 @@ export class SyncHistory { } public addSyncHistoryUpdateListener( - listener: (stats: HistoryStats) => void + listener: (stats: HistoryStats) => unknown ): void { this.syncHistoryUpdateListeners.push(listener); listener({ ...this.status }); diff --git a/frontend/sync-client/src/utils/create-promise.ts b/frontend/sync-client/src/utils/create-promise.ts index 4004ac81..959183f1 100644 --- a/frontend/sync-client/src/utils/create-promise.ts +++ b/frontend/sync-client/src/utils/create-promise.ts @@ -2,13 +2,13 @@ * A type-safe utility function to create a Promise with resolve and reject functions. * @returns A tuple containing a Promise, a resolve function, and a reject function. */ -export function createPromise(): [ +export function createPromise(): [ Promise, - (value: T) => void, - (error: unknown) => void + (value: T) => unknown, + (error: unknown) => unknown ] { - let resolve: undefined | ((resolved: T) => void) = undefined; - let reject: undefined | ((error: unknown) => void) = undefined; + let resolve: undefined | ((resolved: T) => unknown) = undefined; + let reject: undefined | ((error: unknown) => unknown) = undefined; const creationPromise = new Promise( (resolve_, reject_) => ((resolve = resolve_), (reject = reject_)) diff --git a/frontend/test-client/src/agent/mock-client.ts b/frontend/test-client/src/agent/mock-client.ts index 73235298..2833ba29 100644 --- a/frontend/test-client/src/agent/mock-client.ts +++ b/frontend/test-client/src/agent/mock-client.ts @@ -37,7 +37,7 @@ export class MockClient implements FileSystemOperations { fs: this, persistence: { load: async () => this.data, - save: async (data) => void (this.data = data) + save: async (data) => (this.data = data) }, fetch: fetchImplementation, webSocket: webSocketImplementation @@ -78,9 +78,9 @@ export class MockClient implements FileSystemOperations { ); this.localFiles.set(path, newContent); - this.executeFileOperation(() => { - void this.client.syncLocallyCreatedFile(path); - }); + this.executeFileOperation(async () => + this.client.syncLocallyCreatedFile(path) + ); } public async createDirectory(_path: RelativePath): Promise { @@ -120,11 +120,11 @@ export class MockClient implements FileSystemOperations { `Updated file ${path} with:\n current content: ${currentContent}\n new content: ${newContent}` ); - this.executeFileOperation(() => { - void this.client.syncLocallyUpdatedFile({ + this.executeFileOperation(async () => + this.client.syncLocallyUpdatedFile({ relativePath: path - }); - }); + }) + ); return newContent; } @@ -137,13 +137,13 @@ export class MockClient implements FileSystemOperations { `Updated file ${path} with:\n new content: ${new TextDecoder().decode(content)}` ); - this.executeFileOperation(() => { + this.executeFileOperation(async () => { if (hasExisted) { - void this.client.syncLocallyUpdatedFile({ + return this.client.syncLocallyUpdatedFile({ relativePath: path }); } else { - void this.client.syncLocallyCreatedFile(path); + return this.client.syncLocallyCreatedFile(path); } }); } @@ -154,9 +154,9 @@ export class MockClient implements FileSystemOperations { ); this.localFiles.delete(path); - this.executeFileOperation(() => { - void this.client.syncLocallyDeletedFile(path); - }); + this.executeFileOperation(async () => + this.client.syncLocallyDeletedFile(path) + ); } public async rename( @@ -176,15 +176,15 @@ export class MockClient implements FileSystemOperations { `Renamed file: ${oldPath} -> ${newPath} with:\n content ${new TextDecoder().decode(file)}` ); - this.executeFileOperation(() => { - void this.client.syncLocallyUpdatedFile({ + this.executeFileOperation(async () => + this.client.syncLocallyUpdatedFile({ oldPath, relativePath: newPath - }); - }); + }) + ); } - private executeFileOperation(callback: () => void): void { + private executeFileOperation(callback: () => unknown): void { if (this.useSlowFileEvents) { // we aren't the best client and it takes some time to notice changes setTimeout(callback, Math.random() * 100);