mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-05-14 03:21:17 +00:00
chore: ran prettier
This commit is contained in:
@@ -257,12 +257,12 @@ describe("daemon command", () => {
|
||||
// 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
|
||||
const expectedIntervals = [
|
||||
baseMs * 2, // after failure 1: 60000
|
||||
baseMs * 4, // after failure 2: 120000
|
||||
baseMs * 8, // after failure 3: 240000
|
||||
300_000, // after failure 4 (would be 480000, capped)
|
||||
300_000, // after failure 5 (cap)
|
||||
300_000, // after failure 6 (cap)
|
||||
baseMs * 2, // after failure 1: 60000
|
||||
baseMs * 4, // after failure 2: 120000
|
||||
baseMs * 8, // after failure 3: 240000
|
||||
300_000, // after failure 4 (would be 480000, capped)
|
||||
300_000, // after failure 5 (cap)
|
||||
300_000, // after failure 6 (cap)
|
||||
];
|
||||
|
||||
for (const expected of expectedIntervals) {
|
||||
|
||||
@@ -43,10 +43,13 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
|
||||
|
||||
// 3. Re-enable sync.
|
||||
const restoreSyncSettings = async () => {
|
||||
await core.services.setting.applyPartial({
|
||||
...context.originalSyncSettings,
|
||||
suspendFileWatching: false,
|
||||
}, true);
|
||||
await core.services.setting.applyPartial(
|
||||
{
|
||||
...context.originalSyncSettings,
|
||||
suspendFileWatching: false,
|
||||
},
|
||||
true
|
||||
);
|
||||
// applySettings fires the full lifecycle: onSuspending → onResumed.
|
||||
// ModuleReplicatorCouchDB starts continuous replication on onResumed
|
||||
// via fireAndForget.
|
||||
@@ -54,10 +57,13 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
|
||||
// Lifecycle events (onSuspending) may re-enable suspension flags.
|
||||
// Clear them explicitly after the lifecycle completes. applyPartial
|
||||
// with true is a direct store write — it does not re-trigger lifecycle.
|
||||
await core.services.setting.applyPartial({
|
||||
suspendFileWatching: false,
|
||||
suspendParseReplicationResult: false,
|
||||
}, true);
|
||||
await core.services.setting.applyPartial(
|
||||
{
|
||||
suspendFileWatching: false,
|
||||
suspendParseReplicationResult: false,
|
||||
},
|
||||
true
|
||||
);
|
||||
};
|
||||
if (options.interval) {
|
||||
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);
|
||||
console.error(`[Daemon] Poll error (${consecutiveFailures} consecutive):`, err);
|
||||
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);
|
||||
@@ -99,9 +107,11 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
|
||||
log("LiveSync active");
|
||||
const currentSettings = core.services.setting.currentSettings();
|
||||
if (!currentSettings.liveSync && !currentSettings.syncOnStart) {
|
||||
console.error("[Daemon] Warning: liveSync and syncOnStart are both disabled in settings. " +
|
||||
"No sync will occur. Set liveSync=true in your settings file for continuous sync, " +
|
||||
"or use --interval for polling mode.");
|
||||
console.error(
|
||||
"[Daemon] Warning: liveSync and syncOnStart are both disabled in settings. " +
|
||||
"No sync will occur. Set liveSync=true in your settings file for continuous sync, " +
|
||||
"or use --interval for polling mode."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,16 @@ export interface CLICommandContext {
|
||||
databasePath: string;
|
||||
core: LiveSyncBaseCore<ServiceContext, any>;
|
||||
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([
|
||||
|
||||
@@ -280,16 +280,13 @@ export async function main() {
|
||||
// chokidar's ignored option is populated when beginWatch() fires during onLoad().
|
||||
const watchEnabled = options.command === "daemon";
|
||||
const vaultPath =
|
||||
options.command === "mirror" && options.commandArgs[0]
|
||||
? path.resolve(options.commandArgs[0])
|
||||
: databasePath;
|
||||
options.command === "mirror" && options.commandArgs[0] ? path.resolve(options.commandArgs[0]) : databasePath;
|
||||
let ignoreRules: IgnoreRules | undefined;
|
||||
if (options.command === "daemon" || options.command === "mirror") {
|
||||
ignoreRules = new IgnoreRules(vaultPath);
|
||||
await ignoreRules.load();
|
||||
}
|
||||
|
||||
|
||||
// Create service context and hub
|
||||
const context = new NodeServiceContext(databasePath);
|
||||
const serviceHubInstance = new NodeServiceHub<NodeServiceContext>(databasePath, context);
|
||||
|
||||
@@ -97,7 +97,11 @@ class CLIConverterAdapter implements IStorageEventConverterAdapter<NodeFile> {
|
||||
class CLIWatchAdapter implements IStorageEventWatchAdapter {
|
||||
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 {
|
||||
return {
|
||||
|
||||
@@ -60,10 +60,7 @@ describe("CLIStorageEventManagerAdapter", () => {
|
||||
await adapter.watch.beginWatch(handlers);
|
||||
|
||||
expect(chokidar.watch).toHaveBeenCalledTimes(1);
|
||||
expect(chokidar.watch).toHaveBeenCalledWith(
|
||||
"/base",
|
||||
expect.objectContaining({ ignoreInitial: true })
|
||||
);
|
||||
expect(chokidar.watch).toHaveBeenCalledWith("/base", expect.objectContaining({ ignoreInitial: true }));
|
||||
});
|
||||
|
||||
it("add event produces NodeFile with correct relative path via onCreate", async () => {
|
||||
|
||||
@@ -25,7 +25,7 @@ export function initialiseServiceModulesCLI(
|
||||
core: LiveSyncBaseCore<ServiceContext, any>,
|
||||
services: InjectableServiceHub<ServiceContext>,
|
||||
ignoreRules?: IgnoreRules,
|
||||
watchEnabled: boolean = false,
|
||||
watchEnabled: boolean = false
|
||||
): ServiceModules {
|
||||
const storageAccessManager = new StorageAccessManager();
|
||||
|
||||
@@ -39,13 +39,19 @@ export function initialiseServiceModulesCLI(
|
||||
});
|
||||
|
||||
// CLI-specific storage event manager
|
||||
const storageEventManager = new StorageEventManagerCLI(basePath, core, {
|
||||
fileProcessing: services.fileProcessing,
|
||||
setting: services.setting,
|
||||
vaultService: services.vault,
|
||||
storageAccessManager: storageAccessManager,
|
||||
APIService: services.API,
|
||||
}, ignoreRules, watchEnabled);
|
||||
const storageEventManager = new StorageEventManagerCLI(
|
||||
basePath,
|
||||
core,
|
||||
{
|
||||
fileProcessing: services.fileProcessing,
|
||||
setting: services.setting,
|
||||
vaultService: services.vault,
|
||||
storageAccessManager: storageAccessManager,
|
||||
APIService: services.API,
|
||||
},
|
||||
ignoreRules,
|
||||
watchEnabled
|
||||
);
|
||||
|
||||
// Close the file watcher during graceful shutdown so the process can exit cleanly.
|
||||
services.appLifecycle.onUnload.addHandler(async () => {
|
||||
|
||||
@@ -55,7 +55,9 @@ export class IgnoreRules {
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
this._addPattern(trimmed);
|
||||
@@ -105,7 +107,7 @@ export class IgnoreRules {
|
||||
if (raw.startsWith("!")) {
|
||||
throw new Error(
|
||||
`[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));
|
||||
|
||||
@@ -122,10 +122,7 @@ describe("IgnoreRules", () => {
|
||||
describe("load() with comments and blank lines", () => {
|
||||
it("skips # comment lines and blank lines", async () => {
|
||||
const vaultPath = await createVault();
|
||||
await writeIgnoreFile(
|
||||
vaultPath,
|
||||
"# This is a comment\n\n \n*.tmp\n# another comment\nbuild/\n"
|
||||
);
|
||||
await writeIgnoreFile(vaultPath, "# This is a comment\n\n \n*.tmp\n# another comment\nbuild/\n");
|
||||
const rules = new IgnoreRules(vaultPath);
|
||||
await rules.load();
|
||||
expect(rules.shouldIgnore("scratch.tmp")).toBe(true);
|
||||
|
||||
@@ -47,7 +47,8 @@ function injectBanner(): import("vite").Plugin {
|
||||
// Insert after the shebang line if present, otherwise at the top.
|
||||
if (chunk.code.startsWith("#!")) {
|
||||
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 {
|
||||
chunk.code = fileReaderPolyfillBanner + chunk.code;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user