diff --git a/frontend/obsidian-plugin/src/obisidan-event-handler.ts b/frontend/obsidian-plugin/src/obisidan-event-handler.ts index 67ae8efe..b2d58b70 100644 --- a/frontend/obsidian-plugin/src/obisidan-event-handler.ts +++ b/frontend/obsidian-plugin/src/obisidan-event-handler.ts @@ -1,5 +1,4 @@ -import type { SyncClient, Syncer } from "sync-client"; -import { Logger } from "sync-client"; +import type { SyncClient } from "sync-client"; import type { TAbstractFile } from "obsidian"; import { TFile } from "obsidian"; diff --git a/frontend/obsidian-plugin/src/obsidian-file-system.ts b/frontend/obsidian-plugin/src/obsidian-file-system.ts index 68642c15..f9a5d681 100644 --- a/frontend/obsidian-plugin/src/obsidian-file-system.ts +++ b/frontend/obsidian-plugin/src/obsidian-file-system.ts @@ -1,5 +1,6 @@ -import { normalizePath, Stat, Vault } from "obsidian"; -import { FileSystemOperations, RelativePath } from "sync-client"; +import type { Stat, Vault } from "obsidian"; +import { normalizePath } from "obsidian"; +import type { FileSystemOperations, RelativePath } from "sync-client"; export class ObsidianFileSystemOperations implements FileSystemOperations { public constructor(private readonly vault: Vault) {} @@ -17,6 +18,7 @@ export class ObsidianFileSystemOperations implements FileSystemOperations { public async write(path: RelativePath, content: Uint8Array): Promise { return this.vault.adapter.writeBinary( normalizePath(path), + // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion content.buffer as ArrayBuffer ); } diff --git a/frontend/obsidian-plugin/src/views/history-view.ts b/frontend/obsidian-plugin/src/views/history-view.ts index 3fa4f328..457836da 100644 --- a/frontend/obsidian-plugin/src/views/history-view.ts +++ b/frontend/obsidian-plugin/src/views/history-view.ts @@ -3,7 +3,7 @@ import { ItemView, setIcon } from "obsidian"; import { intlFormatDistance } from "date-fns"; import type { HistoryEntry, SyncClient } from "sync-client"; -import { SyncType, SyncSource, SyncStatus, Logger } from "sync-client"; +import { SyncType, SyncSource, SyncStatus } from "sync-client"; export class HistoryView extends ItemView { public static readonly TYPE = "history-view"; @@ -60,6 +60,7 @@ export class HistoryView extends ItemView { } element.createEl("span", { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment text: entry.relativePath }); diff --git a/frontend/sync-client/src/file-operations/file-operations.ts b/frontend/sync-client/src/file-operations/file-operations.ts index ec9ef1a0..8fe2a3fd 100644 --- a/frontend/sync-client/src/file-operations/file-operations.ts +++ b/frontend/sync-client/src/file-operations/file-operations.ts @@ -1,6 +1,6 @@ -import { Logger } from "src/tracing/logger"; -import { FileSystemOperations } from "./filesystem-operations"; -import { RelativePath } from "src/persistence/database"; +import type { Logger } from "src/tracing/logger"; +import type { FileSystemOperations } from "./filesystem-operations"; +import type { RelativePath } from "src/persistence/database"; import { isBinary, isFileTypeMergable, mergeText } from "sync_lib"; export class FileOperations { @@ -138,7 +138,7 @@ export class FileOperations { await this.fs.rename(oldPath, newPath); } - public isFileEligibleForSync(path: RelativePath): boolean { + public isFileEligibleForSync(_path: RelativePath): boolean { return true; // TODO: figure this out // if (Platform.isDesktopApp) { diff --git a/frontend/sync-client/src/file-operations/filesystem-operations.ts b/frontend/sync-client/src/file-operations/filesystem-operations.ts index 32bdcdfe..b58d3c23 100644 --- a/frontend/sync-client/src/file-operations/filesystem-operations.ts +++ b/frontend/sync-client/src/file-operations/filesystem-operations.ts @@ -1,17 +1,17 @@ -import { RelativePath } from "src/persistence/database"; +import type { RelativePath } from "src/persistence/database"; export interface FileSystemOperations { - listAllFiles(): Promise; - read(path: RelativePath): Promise; - write(path: RelativePath, content: Uint8Array): Promise; - atomicUpdateText( + listAllFiles: () => Promise; + read: (path: RelativePath) => Promise; + write: (path: RelativePath, content: Uint8Array) => Promise; + atomicUpdateText: ( path: RelativePath, updater: (currentContent: string) => string - ): Promise; - getFileSize(path: RelativePath): Promise; - getModificationTime(path: RelativePath): Promise; - exists(path: RelativePath): Promise; - createDirectory(path: RelativePath): Promise; - delete(path: RelativePath): Promise; - rename(oldPath: RelativePath, newPath: RelativePath): Promise; + ) => Promise; + getFileSize: (path: RelativePath) => Promise; + getModificationTime: (path: RelativePath) => Promise; + exists: (path: RelativePath) => Promise; + createDirectory: (path: RelativePath) => Promise; + delete: (path: RelativePath) => Promise; + rename: (oldPath: RelativePath, newPath: RelativePath) => Promise; } diff --git a/frontend/sync-client/src/persistence/database.ts b/frontend/sync-client/src/persistence/database.ts index dc048adb..2926af10 100644 --- a/frontend/sync-client/src/persistence/database.ts +++ b/frontend/sync-client/src/persistence/database.ts @@ -8,7 +8,7 @@ export interface DocumentMetadata { hash: string; } -import { Logger } from "src/tracing/logger"; +import type { Logger } from "src/tracing/logger"; export interface StoredDatabase { documents: Map; diff --git a/frontend/sync-client/src/persistence/settings.ts b/frontend/sync-client/src/persistence/settings.ts index fa732092..947aa505 100644 --- a/frontend/sync-client/src/persistence/settings.ts +++ b/frontend/sync-client/src/persistence/settings.ts @@ -1,4 +1,5 @@ -import { Logger, LogLevel } from "src/tracing/logger"; +import type { Logger } from "src/tracing/logger"; +import { LogLevel } from "src/tracing/logger"; export interface SyncSettings { remoteUri: string; diff --git a/frontend/sync-client/src/services/sync-service.ts b/frontend/sync-client/src/services/sync-service.ts index f49a90d2..daf21a24 100644 --- a/frontend/sync-client/src/services/sync-service.ts +++ b/frontend/sync-client/src/services/sync-service.ts @@ -6,7 +6,7 @@ import type { RelativePath, VaultUpdateId } from "../persistence/database"; -import { Logger } from "src/tracing/logger"; +import type { Logger } from "src/tracing/logger"; import { retriedFetchFactory } from "src/utils/retried-fetch"; import type { SyncSettings } from "dist/types"; import type { Settings } from "src/persistence/settings"; diff --git a/frontend/sync-client/src/sync-client.ts b/frontend/sync-client/src/sync-client.ts index 5e7d8f2d..009a87d3 100644 --- a/frontend/sync-client/src/sync-client.ts +++ b/frontend/sync-client/src/sync-client.ts @@ -8,7 +8,7 @@ import { Settings } from "./persistence/settings"; import type { CheckConnectionResult } from "./services/sync-service"; import { SyncService } from "./services/sync-service"; import { Syncer } from "./sync-operations/syncer"; -import { FileSystemOperations } from "./file-operations/filesystem-operations"; +import type { FileSystemOperations } from "./file-operations/filesystem-operations"; import { FileOperations } from "./file-operations/file-operations"; export class SyncClient { @@ -39,6 +39,10 @@ export class SyncClient { return this._logger; } + public get documentCount(): number { + return this._database.getDocuments().size; + } + public static async create( fs: FileSystemOperations, persistence: PersistenceProvider @@ -124,10 +128,6 @@ export class SyncClient { return client; } - public get documentCount(): number { - return this._database.getDocuments().size; - } - public async checkConnection(): Promise { return this._syncService.checkConnection(); } diff --git a/frontend/sync-client/src/sync-operations/syncer.ts b/frontend/sync-client/src/sync-operations/syncer.ts index d99eb065..d4ec5c93 100644 --- a/frontend/sync-client/src/sync-operations/syncer.ts +++ b/frontend/sync-client/src/sync-operations/syncer.ts @@ -1,20 +1,16 @@ -import type { - Database, - DocumentMetadata, - RelativePath -} from "../persistence/database"; +import type { Database, RelativePath } from "../persistence/database"; import type { SyncService } from "src/services/sync-service"; -import { Logger } from "src/tracing/logger"; +import type { Logger } from "src/tracing/logger"; import type { SyncHistory } from "src/tracing/sync-history"; import { SyncSource, SyncStatus, SyncType } from "src/tracing/sync-history"; import { unlockDocument, waitForDocumentLock } from "./document-lock"; import PQueue from "p-queue"; -import { EMPTY_HASH, hash } from "src/utils/hash"; +import { hash } from "src/utils/hash"; import type { components } from "src/services/types"; import { deserialize } from "src/utils/deserialize"; import type { Settings } from "src/persistence/settings"; -import { FileOperations } from "src/file-operations/file-operations"; +import type { FileOperations } from "src/file-operations/file-operations"; import { findMatchingFileBasedOnHash } from "src/utils/find-matching-file-based-on-hash"; export class Syncer { @@ -75,7 +71,7 @@ export class Syncer { ); } - public waitForSyncQueue(): Promise { + public async waitForSyncQueue(): Promise { return this.syncQueue.onEmpty(); } diff --git a/frontend/sync-client/src/tracing/sync-history.ts b/frontend/sync-client/src/tracing/sync-history.ts index f4609d81..a6523b5f 100644 --- a/frontend/sync-client/src/tracing/sync-history.ts +++ b/frontend/sync-client/src/tracing/sync-history.ts @@ -1,5 +1,5 @@ import type { RelativePath } from "src/persistence/database"; -import { Logger } from "./logger"; +import type { Logger } from "./logger"; export interface CommonHistoryEntry { status: SyncStatus; @@ -47,7 +47,7 @@ export class SyncHistory { error: 0 }; - public constructor(private logger: Logger) {} + public constructor(private readonly logger: Logger) {} public getEntries(): HistoryEntry[] { return [...this.entries]; diff --git a/frontend/sync-client/src/utils/find-matching-file-based-on-hash.ts b/frontend/sync-client/src/utils/find-matching-file-based-on-hash.ts index ecd54c85..cf0b1cda 100644 --- a/frontend/sync-client/src/utils/find-matching-file-based-on-hash.ts +++ b/frontend/sync-client/src/utils/find-matching-file-based-on-hash.ts @@ -1,4 +1,4 @@ -import { DocumentMetadata, RelativePath } from "src/persistence/database"; +import type { DocumentMetadata, RelativePath } from "src/persistence/database"; import { EMPTY_HASH } from "./hash"; export function findMatchingFileBasedOnHash( diff --git a/frontend/sync-client/src/utils/retried-fetch.ts b/frontend/sync-client/src/utils/retried-fetch.ts index 1a5483c4..d3efcd2d 100644 --- a/frontend/sync-client/src/utils/retried-fetch.ts +++ b/frontend/sync-client/src/utils/retried-fetch.ts @@ -1,6 +1,6 @@ import * as fetchRetryFactory from "fetch-retry"; import type { RequestInitRetryParams } from "fetch-retry"; -import { Logger } from "src/tracing/logger"; +import type { Logger } from "src/tracing/logger"; const fetchWithRetry = fetchRetryFactory.default(fetch); @@ -15,7 +15,7 @@ function getUrlFromInput(input: RequestInfo | URL): string { } export function retriedFetchFactory(logger: Logger) { - return ( + return async ( input: RequestInfo | URL, init: RequestInitRetryParams = {} ): Promise => { diff --git a/frontend/test-client/src/agent/mock-agent.ts b/frontend/test-client/src/agent/mock-agent.ts index c69fae45..7bce4e22 100644 --- a/frontend/test-client/src/agent/mock-agent.ts +++ b/frontend/test-client/src/agent/mock-agent.ts @@ -1,14 +1,15 @@ import { choose } from "../utils/choose"; import { v4 as uuidv4 } from "uuid"; import { assert } from "../utils/assert"; -import { LogLevel, SyncSettings } from "sync-client"; +import type { SyncSettings } from "sync-client"; +import { LogLevel } from "sync-client"; import { MockClient } from "./mock-client"; import chalk from "chalk"; import { sleep } from "../utils/sleep"; export class MockAgent extends MockClient { - private writtenContents: Array = []; - private pendingActions: Array> = []; + private readonly writtenContents: string[] = []; + private readonly pendingActions: Promise[] = []; public constructor( globalFiles: Record, @@ -48,8 +49,8 @@ export class MockAgent extends MockClient { } public async act(): Promise { - let options: Array<() => Promise> = [ - () => { + const options: (() => Promise)[] = [ + async (): Promise => { const file = this.getFileName(); this.client.logger.info(`Decided to create file ${file}`); return this.create( @@ -57,7 +58,7 @@ export class MockAgent extends MockClient { new TextEncoder().encode(this.getContent()) ); }, - () => { + async (): Promise => { this.client.logger.info( `Decided to change fetchChangesUpdateIntervalMs` ); @@ -66,21 +67,21 @@ export class MockAgent extends MockClient { Math.random() * 1000 ); }, - () => { + async (): Promise => { this.client.logger.info(`Decided to disable sync`); return this.client.settings.setSetting("isSyncEnabled", false); }, - () => { + async (): Promise => { this.client.logger.info(`Decided to enable sync`); return this.client.settings.setSetting("isSyncEnabled", true); } ]; - let files = await this.listAllFiles(); + const files = await this.listAllFiles(); if (files.length > 0) { options.push( - () => { + async (): Promise => { const file = choose(files); const newName = this.getFileName(); @@ -89,7 +90,7 @@ export class MockAgent extends MockClient { ); return this.rename(file, newName); }, - () => { + async (): Promise => { const file = choose(files); this.client.logger.info(`Decided to update file ${file}`); @@ -101,23 +102,13 @@ export class MockAgent extends MockClient { ); if (this.doDeletes) { - options.push(() => this.delete(choose(files))); + options.push(async () => this.delete(choose(files))); } } this.pendingActions.push(choose(options)()); } - private getContent() { - const uuid = uuidv4(); - this.writtenContents.push(uuid); - return uuid; - } - - private getFileName() { - return `${this.name}-${uuidv4()}.md`; - } - public async finish(): Promise { await Promise.all(this.pendingActions); await this.client.settings.setSetting("isSyncEnabled", true); @@ -178,7 +169,7 @@ export class MockAgent extends MockClient { `Content ${content} found in ${found.length} files` ); - const file = found[0]; + const [file] = found; assert( new TextDecoder().decode(file).split(content).length === 2, `Content ${content} found more than once in a file` @@ -186,4 +177,14 @@ export class MockAgent extends MockClient { } } } + + private getContent(): string { + const uuid = uuidv4(); + this.writtenContents.push(uuid); + return uuid; + } + + private getFileName(): string { + return `${this.name}-${uuidv4()}.md`; + } } diff --git a/frontend/test-client/src/agent/mock-client.ts b/frontend/test-client/src/agent/mock-client.ts index 5766bc02..0ce689c4 100644 --- a/frontend/test-client/src/agent/mock-client.ts +++ b/frontend/test-client/src/agent/mock-client.ts @@ -1,9 +1,9 @@ -import { - SyncClient, +import type { RelativePath, FileSystemOperations, SyncSettings } from "sync-client"; +import { SyncClient } from "sync-client"; import { assert } from "../utils/assert"; export class MockClient implements FileSystemOperations { @@ -15,7 +15,7 @@ export class MockClient implements FileSystemOperations { private readonly initialSettings: Partial ) {} - public async init() { + public async init(): Promise { let _data: unknown = ""; this.client = await SyncClient.create(this, { @@ -23,12 +23,14 @@ export class MockClient implements FileSystemOperations { save: async (data: unknown) => void (_data = data) }); - Object.keys(this.initialSettings).forEach((key) => { - this.client.settings.setSetting( - key as keyof SyncSettings, - this.initialSettings[key as keyof SyncSettings] - ); - }); + await Promise.all( + Object.keys(this.initialSettings).map(async (key) => { + return this.client.settings.setSetting( + key as keyof SyncSettings, + this.initialSettings[key as keyof SyncSettings] + ); + }) + ); assert( (await this.client.checkConnection()).isSuccessful, @@ -37,7 +39,7 @@ export class MockClient implements FileSystemOperations { } public async listAllFiles(): Promise { - return Object.keys(this.localFiles) as RelativePath[]; + return Object.keys(this.localFiles); } public async read(path: RelativePath): Promise { @@ -77,7 +79,9 @@ export class MockClient implements FileSystemOperations { this.client.syncer.syncLocallyCreatedFile(path, new Date()); } - public async createDirectory(path: RelativePath): Promise {} + public async createDirectory(path: RelativePath): Promise { + // This doesn't mean anything in our virtual FS representation + } public async atomicUpdateText( path: RelativePath, diff --git a/frontend/test-client/src/cli.ts b/frontend/test-client/src/cli.ts index 0d59f796..3c0c8d45 100644 --- a/frontend/test-client/src/cli.ts +++ b/frontend/test-client/src/cli.ts @@ -1,4 +1,4 @@ -import { SyncSettings } from "sync-client"; +import type { SyncSettings } from "sync-client"; import { MockAgent } from "./agent/mock-agent"; import { sleep } from "./utils/sleep"; import { v4 as uuidv4 } from "uuid"; @@ -55,14 +55,14 @@ async function runTest(): Promise { ) ]; - await Promise.all(clients.map((client) => client.init())); + await Promise.all(clients.map(async (client) => client.init())); for (let i = 0; i < iterations; i++) { - await Promise.all(clients.map((client) => client.act())); + await Promise.all(clients.map(async (client) => client.act())); await sleep(100); } - await Promise.all(clients.map((client) => client.finish())); + await Promise.all(clients.map(async (client) => client.finish())); console.info("Agents finished successfully"); @@ -83,4 +83,11 @@ async function runTest(): Promise { console.info("Test completed successfully"); } -runTest(); +runTest() + .then(() => { + process.exit(0); + }) + .catch((err: unknown) => { + console.error(err); + process.exit(1); + }); diff --git a/frontend/test-client/src/utils/sleep.ts b/frontend/test-client/src/utils/sleep.ts index 8b8bcd5e..638fc019 100644 --- a/frontend/test-client/src/utils/sleep.ts +++ b/frontend/test-client/src/utils/sleep.ts @@ -1,3 +1,3 @@ -export function sleep(ms: number): Promise { +export async function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); }