chore: ran prettier

This commit is contained in:
vorotamoroz
2026-05-13 14:10:56 +01:00
parent de2397dc3f
commit 6a9bba702c
12 changed files with 73 additions and 49 deletions
+6 -5
View File
@@ -35,11 +35,12 @@ export class LiveSyncBaseCore<
TCommands extends IMinimumLiveSyncCommands = IMinimumLiveSyncCommands, TCommands extends IMinimumLiveSyncCommands = IMinimumLiveSyncCommands,
> >
implements implements
LiveSyncLocalDBEnv, LiveSyncLocalDBEnv,
LiveSyncReplicatorEnv, LiveSyncReplicatorEnv,
LiveSyncJournalReplicatorEnv, LiveSyncJournalReplicatorEnv,
LiveSyncCouchDBReplicatorEnv, LiveSyncCouchDBReplicatorEnv,
HasSettings<ObsidianLiveSyncSettings> { HasSettings<ObsidianLiveSyncSettings>
{
addOns = [] as TCommands[]; addOns = [] as TCommands[];
/** /**
@@ -257,12 +257,12 @@ describe("daemon command", () => {
// failure 1: 30000*2=60000, failure 2: 30000*4=120000, // failure 1: 30000*2=60000, failure 2: 30000*4=120000,
// failure 3: 30000*8=240000, failure 4: 30000*16=480000→capped, 5→cap, 6→cap // failure 3: 30000*8=240000, failure 4: 30000*16=480000→capped, 5→cap, 6→cap
const expectedIntervals = [ const expectedIntervals = [
baseMs * 2, // after failure 1: 60000 baseMs * 2, // after failure 1: 60000
baseMs * 4, // after failure 2: 120000 baseMs * 4, // after failure 2: 120000
baseMs * 8, // after failure 3: 240000 baseMs * 8, // after failure 3: 240000
300_000, // after failure 4 (would be 480000, capped) 300_000, // after failure 4 (would be 480000, capped)
300_000, // after failure 5 (cap) 300_000, // after failure 5 (cap)
300_000, // after failure 6 (cap) 300_000, // after failure 6 (cap)
]; ];
for (const expected of expectedIntervals) { for (const expected of expectedIntervals) {
+22 -12
View File
@@ -43,10 +43,13 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
// 3. Re-enable sync. // 3. Re-enable sync.
const restoreSyncSettings = async () => { const restoreSyncSettings = async () => {
await core.services.setting.applyPartial({ await core.services.setting.applyPartial(
...context.originalSyncSettings, {
suspendFileWatching: false, ...context.originalSyncSettings,
}, true); suspendFileWatching: false,
},
true
);
// applySettings fires the full lifecycle: onSuspending → onResumed. // applySettings fires the full lifecycle: onSuspending → onResumed.
// ModuleReplicatorCouchDB starts continuous replication on onResumed // ModuleReplicatorCouchDB starts continuous replication on onResumed
// via fireAndForget. // via fireAndForget.
@@ -54,10 +57,13 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
// Lifecycle events (onSuspending) may re-enable suspension flags. // Lifecycle events (onSuspending) may re-enable suspension flags.
// Clear them explicitly after the lifecycle completes. applyPartial // Clear them explicitly after the lifecycle completes. applyPartial
// with true is a direct store write — it does not re-trigger lifecycle. // with true is a direct store write — it does not re-trigger lifecycle.
await core.services.setting.applyPartial({ await core.services.setting.applyPartial(
suspendFileWatching: false, {
suspendParseReplicationResult: false, suspendFileWatching: false,
}, true); suspendParseReplicationResult: false,
},
true
);
}; };
if (options.interval) { if (options.interval) {
log(`Polling mode: syncing every ${options.interval}s`); log(`Polling mode: syncing every ${options.interval}s`);
@@ -80,7 +86,9 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
currentIntervalMs = Math.min(baseIntervalMs * Math.pow(2, consecutiveFailures), maxIntervalMs); currentIntervalMs = Math.min(baseIntervalMs * Math.pow(2, consecutiveFailures), maxIntervalMs);
console.error(`[Daemon] Poll error (${consecutiveFailures} consecutive):`, err); console.error(`[Daemon] Poll error (${consecutiveFailures} consecutive):`, err);
if (consecutiveFailures >= 5) { if (consecutiveFailures >= 5) {
console.error(`[Daemon] Warning: ${consecutiveFailures} consecutive failures, backing off to ${Math.round(currentIntervalMs / 1000)}s`); console.error(
`[Daemon] Warning: ${consecutiveFailures} consecutive failures, backing off to ${Math.round(currentIntervalMs / 1000)}s`
);
} }
} }
pollTimer = setTimeout(poll, currentIntervalMs); pollTimer = setTimeout(poll, currentIntervalMs);
@@ -99,9 +107,11 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
log("LiveSync active"); log("LiveSync active");
const currentSettings = core.services.setting.currentSettings(); const currentSettings = core.services.setting.currentSettings();
if (!currentSettings.liveSync && !currentSettings.syncOnStart) { if (!currentSettings.liveSync && !currentSettings.syncOnStart) {
console.error("[Daemon] Warning: liveSync and syncOnStart are both disabled in settings. " + console.error(
"No sync will occur. Set liveSync=true in your settings file for continuous sync, " + "[Daemon] Warning: liveSync and syncOnStart are both disabled in settings. " +
"or use --interval for polling mode."); "No sync will occur. Set liveSync=true in your settings file for continuous sync, " +
"or use --interval for polling mode."
);
} }
} }
+10 -1
View File
@@ -37,7 +37,16 @@ export interface CLICommandContext {
databasePath: string; databasePath: string;
core: LiveSyncBaseCore<ServiceContext, any>; core: LiveSyncBaseCore<ServiceContext, any>;
settingsPath: string; settingsPath: string;
originalSyncSettings: Pick<ObsidianLiveSyncSettings, "liveSync" | "syncOnStart" | "periodicReplication" | "syncOnSave" | "syncOnEditorSave" | "syncOnFileOpen" | "syncAfterMerge">; originalSyncSettings: Pick<
ObsidianLiveSyncSettings,
| "liveSync"
| "syncOnStart"
| "periodicReplication"
| "syncOnSave"
| "syncOnEditorSave"
| "syncOnFileOpen"
| "syncAfterMerge"
>;
} }
export const VALID_COMMANDS = new Set([ export const VALID_COMMANDS = new Set([
+1 -4
View File
@@ -280,16 +280,13 @@ export async function main() {
// chokidar's ignored option is populated when beginWatch() fires during onLoad(). // chokidar's ignored option is populated when beginWatch() fires during onLoad().
const watchEnabled = options.command === "daemon"; const watchEnabled = options.command === "daemon";
const vaultPath = const vaultPath =
options.command === "mirror" && options.commandArgs[0] options.command === "mirror" && options.commandArgs[0] ? path.resolve(options.commandArgs[0]) : databasePath;
? path.resolve(options.commandArgs[0])
: databasePath;
let ignoreRules: IgnoreRules | undefined; let ignoreRules: IgnoreRules | undefined;
if (options.command === "daemon" || options.command === "mirror") { if (options.command === "daemon" || options.command === "mirror") {
ignoreRules = new IgnoreRules(vaultPath); ignoreRules = new IgnoreRules(vaultPath);
await ignoreRules.load(); await ignoreRules.load();
} }
// Create service context and hub // Create service context and hub
const context = new NodeServiceContext(databasePath); const context = new NodeServiceContext(databasePath);
const serviceHubInstance = new NodeServiceHub<NodeServiceContext>(databasePath, context); const serviceHubInstance = new NodeServiceHub<NodeServiceContext>(databasePath, context);
@@ -97,7 +97,11 @@ class CLIConverterAdapter implements IStorageEventConverterAdapter<NodeFile> {
class CLIWatchAdapter implements IStorageEventWatchAdapter { class CLIWatchAdapter implements IStorageEventWatchAdapter {
private _watcher: FSWatcher | undefined; private _watcher: FSWatcher | undefined;
constructor(private basePath: string, private ignoreRules?: IgnoreRules, private watchEnabled: boolean = false) {} constructor(
private basePath: string,
private ignoreRules?: IgnoreRules,
private watchEnabled: boolean = false
) {}
private _toNodeFile(filePath: string, stats: Stats | undefined): NodeFile { private _toNodeFile(filePath: string, stats: Stats | undefined): NodeFile {
return { return {
@@ -60,10 +60,7 @@ describe("CLIStorageEventManagerAdapter", () => {
await adapter.watch.beginWatch(handlers); await adapter.watch.beginWatch(handlers);
expect(chokidar.watch).toHaveBeenCalledTimes(1); expect(chokidar.watch).toHaveBeenCalledTimes(1);
expect(chokidar.watch).toHaveBeenCalledWith( expect(chokidar.watch).toHaveBeenCalledWith("/base", expect.objectContaining({ ignoreInitial: true }));
"/base",
expect.objectContaining({ ignoreInitial: true })
);
}); });
it("add event produces NodeFile with correct relative path via onCreate", async () => { it("add event produces NodeFile with correct relative path via onCreate", async () => {
@@ -25,7 +25,7 @@ export function initialiseServiceModulesCLI(
core: LiveSyncBaseCore<ServiceContext, any>, core: LiveSyncBaseCore<ServiceContext, any>,
services: InjectableServiceHub<ServiceContext>, services: InjectableServiceHub<ServiceContext>,
ignoreRules?: IgnoreRules, ignoreRules?: IgnoreRules,
watchEnabled: boolean = false, watchEnabled: boolean = false
): ServiceModules { ): ServiceModules {
const storageAccessManager = new StorageAccessManager(); const storageAccessManager = new StorageAccessManager();
@@ -39,13 +39,19 @@ export function initialiseServiceModulesCLI(
}); });
// CLI-specific storage event manager // CLI-specific storage event manager
const storageEventManager = new StorageEventManagerCLI(basePath, core, { const storageEventManager = new StorageEventManagerCLI(
fileProcessing: services.fileProcessing, basePath,
setting: services.setting, core,
vaultService: services.vault, {
storageAccessManager: storageAccessManager, fileProcessing: services.fileProcessing,
APIService: services.API, setting: services.setting,
}, ignoreRules, watchEnabled); vaultService: services.vault,
storageAccessManager: storageAccessManager,
APIService: services.API,
},
ignoreRules,
watchEnabled
);
// Close the file watcher during graceful shutdown so the process can exit cleanly. // Close the file watcher during graceful shutdown so the process can exit cleanly.
services.appLifecycle.onUnload.addHandler(async () => { services.appLifecycle.onUnload.addHandler(async () => {
+4 -2
View File
@@ -55,7 +55,9 @@ export class IgnoreRules {
continue; continue;
} }
if (trimmed.startsWith("import:")) { if (trimmed.startsWith("import:")) {
console.error(`[IgnoreRules] Warning: unrecognised directive '${trimmed}' — only 'import: .gitignore' is supported`); console.error(
`[IgnoreRules] Warning: unrecognised directive '${trimmed}' — only 'import: .gitignore' is supported`
);
continue; continue;
} }
this._addPattern(trimmed); this._addPattern(trimmed);
@@ -105,7 +107,7 @@ export class IgnoreRules {
if (raw.startsWith("!")) { if (raw.startsWith("!")) {
throw new Error( throw new Error(
`[IgnoreRules] Negation pattern '${raw}' is not supported. ` + `[IgnoreRules] Negation pattern '${raw}' is not supported. ` +
`Remove it from .livesync/ignore or use a separate include/exclude file.` `Remove it from .livesync/ignore or use a separate include/exclude file.`
); );
} }
this.patterns.push(this._normalisePattern(raw)); this.patterns.push(this._normalisePattern(raw));
@@ -122,10 +122,7 @@ describe("IgnoreRules", () => {
describe("load() with comments and blank lines", () => { describe("load() with comments and blank lines", () => {
it("skips # comment lines and blank lines", async () => { it("skips # comment lines and blank lines", async () => {
const vaultPath = await createVault(); const vaultPath = await createVault();
await writeIgnoreFile( await writeIgnoreFile(vaultPath, "# This is a comment\n\n \n*.tmp\n# another comment\nbuild/\n");
vaultPath,
"# This is a comment\n\n \n*.tmp\n# another comment\nbuild/\n"
);
const rules = new IgnoreRules(vaultPath); const rules = new IgnoreRules(vaultPath);
await rules.load(); await rules.load();
expect(rules.shouldIgnore("scratch.tmp")).toBe(true); expect(rules.shouldIgnore("scratch.tmp")).toBe(true);
+2 -1
View File
@@ -47,7 +47,8 @@ function injectBanner(): import("vite").Plugin {
// Insert after the shebang line if present, otherwise at the top. // Insert after the shebang line if present, otherwise at the top.
if (chunk.code.startsWith("#!")) { if (chunk.code.startsWith("#!")) {
const newline = chunk.code.indexOf("\n"); const newline = chunk.code.indexOf("\n");
chunk.code = chunk.code.slice(0, newline + 1) + fileReaderPolyfillBanner + chunk.code.slice(newline + 1); chunk.code =
chunk.code.slice(0, newline + 1) + fileReaderPolyfillBanner + chunk.code.slice(newline + 1);
} else { } else {
chunk.code = fileReaderPolyfillBanner + chunk.code; chunk.code = fileReaderPolyfillBanner + chunk.code;
} }
@@ -7,7 +7,7 @@ import type { TFile, App, TFolder } from "obsidian";
* Vault adapter implementation for Obsidian * Vault adapter implementation for Obsidian
*/ */
export class ObsidianVaultAdapter implements IVaultAdapter<TFile> { export class ObsidianVaultAdapter implements IVaultAdapter<TFile> {
constructor(private app: App) { } constructor(private app: App) {}
async read(file: TFile): Promise<string> { async read(file: TFile): Promise<string> {
return await this.app.vault.read(file); return await this.app.vault.read(file);