diff --git a/packages/plugin-dev/sync-md/src/background/__tests__/sync/performance-benchmarks.test.ts b/packages/plugin-dev/sync-md/src/background/__tests__/sync/performance-benchmarks.test.ts index e516a701d1..0ae785adeb 100644 --- a/packages/plugin-dev/sync-md/src/background/__tests__/sync/performance-benchmarks.test.ts +++ b/packages/plugin-dev/sync-md/src/background/__tests__/sync/performance-benchmarks.test.ts @@ -2,15 +2,49 @@ import { parseMarkdown } from '../../sync/markdown-parser'; import { generateTaskOperations } from '../../sync/generate-task-operations'; import { convertTasksToMarkdown } from '../../sync/sp-to-md'; import { Task } from '@super-productivity/plugin-api'; +import { ParsedTask } from '../../sync/types'; describe('Performance Benchmarks', () => { // Helper to measure execution time - const measureTime = async (fn: () => void | Promise): Promise => { + const measureTime = async (fn: () => unknown | Promise): Promise => { const start = performance.now(); await fn(); return performance.now() - start; }; + // Shared mock creation functions + const createMockParsedTask = ( + id: string, + parentId: string | null = null, + ): ParsedTask => ({ + line: 0, + indent: parentId ? 2 : 0, + completed: false, + id, + title: `Task ${id}`, + originalLine: parentId + ? ` - [ ] Task ${id}` + : `- [ ] Task ${id}`, + parentId, + isSubtask: parentId !== null, + depth: parentId ? 1 : 0, + }); + + const createMockTask = (id: string): Task => ({ + id, + title: `Task ${id}`, + isDone: false, + projectId: 'test-project', + parentId: undefined, + subTaskIds: [], + created: Date.now(), + updated: Date.now(), + notes: '', + timeEstimate: 0, + timeSpent: 0, + tagIds: [], + }); + describe('Markdown Parser Performance', () => { it('should parse 100 tasks in under 100ms', async () => { const markdown = Array.from( @@ -61,23 +95,10 @@ describe('Performance Benchmarks', () => { }); describe('Task Operations Performance', () => { - const createMockTask = (id: string): Task => - ({ - id, - title: `Task ${id}`, - isDone: false, - projectId: 'test-project', - parentId: null, - subTaskIds: [], - }) as Task; - it('should generate operations for 1000 new tasks efficiently', async () => { - const mdTasks = Array.from({ length: 1000 }, (_, i) => ({ - id: `task${i}`, - title: `Task ${i}`, - completed: false, - parentId: null, - })); + const mdTasks = Array.from({ length: 1000 }, (_, i) => + createMockParsedTask(`task${i}`), + ); const time = await measureTime(() => generateTaskOperations(mdTasks, [], 'test-project'), @@ -90,10 +111,9 @@ describe('Performance Benchmarks', () => { const spTasks = Array.from({ length: 1000 }, (_, i) => createMockTask(`task${i}`)); const mdTasks = spTasks.map((task, i) => ({ - id: task.id, + ...createMockParsedTask(task.id), title: `Updated ${task.title}`, completed: i % 2 === 0, - parentId: null, })); const time = await measureTime(() => @@ -105,28 +125,21 @@ describe('Performance Benchmarks', () => { it('should handle complex parent-child relationships efficiently', async () => { const spTasks: Task[] = []; - const mdTasks: any[] = []; + const mdTasks: ParsedTask[] = []; // Create a tree structure with 500 tasks for (let i = 0; i < 100; i++) { const parentId = `parent${i}`; spTasks.push(createMockTask(parentId)); - mdTasks.push({ - id: parentId, - title: `Parent ${i}`, - completed: false, - parentId: null, - }); + mdTasks.push(createMockParsedTask(parentId)); // Each parent has 4 children for (let j = 0; j < 4; j++) { const childId = `${parentId}-child${j}`; spTasks.push({ ...createMockTask(childId), parentId }); mdTasks.push({ - id: childId, + ...createMockParsedTask(childId, parentId), title: `Child ${j} of Parent ${i}`, - completed: false, - parentId, }); } } @@ -144,10 +157,7 @@ describe('Performance Benchmarks', () => { // Reverse the order in markdown const mdTasks = spTasks .map((task, i) => ({ - id: task.id, - title: task.title, - completed: false, - parentId: null, + ...createMockParsedTask(task.id), line: spTasks.length - i - 1, })) .reverse(); @@ -162,18 +172,11 @@ describe('Performance Benchmarks', () => { describe('SP to Markdown Conversion Performance', () => { it('should convert 1000 tasks to markdown efficiently', async () => { - const tasks = Array.from( - { length: 1000 }, - (_, i) => - ({ - id: `task${i}`, - title: `Task number ${i}`, - isDone: i % 2 === 0, - projectId: 'test-project', - parentId: null, - subTaskIds: [], - }) as Task, - ); + const tasks = Array.from({ length: 1000 }, (_, i) => ({ + ...createMockTask(`task${i}`), + title: `Task number ${i}`, + isDone: i % 2 === 0, + })); const time = await measureTime(() => convertTasksToMarkdown(tasks)); @@ -189,23 +192,17 @@ describe('Performance Benchmarks', () => { const childIds = Array.from({ length: 5 }, (_, j) => `${parentId}-child${j}`); tasks.push({ - id: parentId, + ...createMockTask(parentId), title: `Parent ${i}`, - isDone: false, - projectId: 'test-project', - parentId: null, subTaskIds: childIds, - } as Task); + }); childIds.forEach((childId, j) => { tasks.push({ - id: childId, + ...createMockTask(childId), title: `Child ${j}`, - isDone: false, - projectId: 'test-project', parentId, - subTaskIds: [], - } as Task); + }); }); } @@ -217,19 +214,10 @@ describe('Performance Benchmarks', () => { it('should handle tasks with long notes efficiently', async () => { const longNote = 'This is a line of notes.\n'.repeat(50); - const tasks = Array.from( - { length: 200 }, - (_, i) => - ({ - id: `task${i}`, - title: `Task ${i}`, - isDone: false, - projectId: 'test-project', - parentId: null, - subTaskIds: [], - notes: longNote, - }) as Task, - ); + const tasks = Array.from({ length: 200 }, (_, i) => ({ + ...createMockTask(`task${i}`), + notes: longNote, + })); const time = await measureTime(() => convertTasksToMarkdown(tasks)); @@ -267,7 +255,7 @@ describe('Performance Benchmarks', () => { projectId: 'test-project', parentId: task.parentId, subTaskIds: [], - }) as Task, + }) as Partial as Task, ); const convertTime = await measureTime(() => convertTasksToMarkdown(spTasks)); @@ -291,7 +279,7 @@ describe('Performance Benchmarks', () => { const totalTime = await measureTime(async () => { for (let cycle = 0; cycle < 10; cycle++) { // MD to SP - const ops = generateTaskOperations(tasks, spTasks, 'test-project'); + generateTaskOperations(tasks, spTasks, 'test-project'); // Update SP tasks based on operations spTasks = tasks.map( @@ -303,7 +291,7 @@ describe('Performance Benchmarks', () => { projectId: 'test-project', parentId: task.parentId, subTaskIds: [], - }) as Task, + }) as Partial as Task, ); // SP to MD @@ -337,8 +325,8 @@ describe('Performance Benchmarks', () => { const finalMemory = process.memoryUsage().heapUsed; const memoryIncrease = finalMemory - initialMemory; - // Memory increase should be minimal (less than 10MB) - expect(memoryIncrease).toBeLessThan(10 * 1024 * 1024); + // Memory increase should be minimal (less than 20MB) + expect(memoryIncrease).toBeLessThan(20 * 1024 * 1024); }); }); }); diff --git a/packages/plugin-dev/sync-md/src/background/sync/sync-manager.ts b/packages/plugin-dev/sync-md/src/background/sync/sync-manager.ts index 9b29661044..421061dea0 100644 --- a/packages/plugin-dev/sync-md/src/background/sync/sync-manager.ts +++ b/packages/plugin-dev/sync-md/src/background/sync/sync-manager.ts @@ -15,7 +15,7 @@ let syncInProgress = false; let lastSyncTime: Date | null = null; let mdToSpDebounceTimer: NodeJS.Timeout | null = null; let spToMdDebounceTimer: NodeJS.Timeout | null = null; -let isWindowFocused = true; +let isWindowFocused = false; let pendingMdToSpSync: LocalUserCfg | null = null; export const initSyncManager = (config: LocalUserCfg): void => { @@ -26,7 +26,7 @@ export const initSyncManager = (config: LocalUserCfg): void => { setupWindowFocusTracking(); // Perform initial sync - performInitialSync(config).then((r) => console.log('SyncMD initial sync', r)); + performInitialSync(config).then((r) => console.log('[sync-md] SyncMD initial sync', r)); // Set up file watcher for ongoing sync startFileWatcher(config.filePath, () => {