From a87735da0b2b733c36803eae3847438eab255052 Mon Sep 17 00:00:00 2001 From: Gordon Mickel Date: Sun, 21 Jul 2024 22:37:10 +0200 Subject: [PATCH] feat: improve file cache handling and normalize paths This commit improves the file cache handling by introducing the `normalizePath` function to ensure consistent path representation. It also updates the cache entries to use ISO string format for `created` and `modified` dates. Additionally, the commit fixes the e2e test for cross-platform compatibility. --- src/utils/file-cache.ts | 39 +++++++++++++++++++++------------- tests/e2e/cli-commands.test.ts | 2 +- tests/unit/file-cache.test.ts | 27 +++++++++++++++++++++-- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/utils/file-cache.ts b/src/utils/file-cache.ts index 1ea01d0..c78733c 100644 --- a/src/utils/file-cache.ts +++ b/src/utils/file-cache.ts @@ -2,6 +2,7 @@ import crypto from 'node:crypto'; import path from 'node:path'; import fs from 'fs-extra'; import type { FileInfo } from '../core/file-processor'; +import { normalizePath } from './normalize-path'; interface CacheEntry { hash: string; @@ -36,8 +37,17 @@ export class FileCache { const content = await fs.readFile(this.cacheFile, 'utf-8'); try { this.cache = JSON.parse(content, (key, value) => { - if (key === 'created' || key === 'modified') { - return new Date(value); + if (typeof value === 'object' && value !== null) { + if (value.type === 'Date') { + return new Date(value.value); + } + if (value.created && value.modified) { + value.created = new Date(value.created); + value.modified = new Date(value.modified); + } + } + if (key === 'path') { + return normalizePath(value); } return value; }); @@ -72,19 +82,18 @@ export class FileCache { await fs.ensureDir(path.dirname(this.cacheFile)); const tempFile = `${this.cacheFile}.tmp`; - // Stringify cache items individually - const cacheEntries = Object.entries(this.cache) - .map(([key, value]) => { - try { - return `"${key}":${JSON.stringify(value)}`; - } catch (error) { - console.warn(`Failed to stringify cache entry for ${key}:`, error); - return null; - } - }) - .filter(Boolean); - - const cacheString = `{${cacheEntries.join(',')}}`; + const cacheString = JSON.stringify(this.cache, (key, value) => { + if (value instanceof Date) { + return { type: 'Date', value: value.toISOString() }; + } + if (key === 'created' || key === 'modified') { + return { type: 'Date', value: new Date(value).toISOString() }; + } + if (key === 'path') { + return normalizePath(value); + } + return value; + }); await fs.writeFile(tempFile, cacheString, 'utf-8'); await fs.rename(tempFile, this.cacheFile); diff --git a/tests/e2e/cli-commands.test.ts b/tests/e2e/cli-commands.test.ts index 44a7c2e..c681fb1 100644 --- a/tests/e2e/cli-commands.test.ts +++ b/tests/e2e/cli-commands.test.ts @@ -279,5 +279,5 @@ describe('CLI Commands', () => { await fs.remove(testDir1); await fs.remove(testDir2); } - }); + }, 30000); }); diff --git a/tests/unit/file-cache.test.ts b/tests/unit/file-cache.test.ts index 90fa109..78d4d83 100644 --- a/tests/unit/file-cache.test.ts +++ b/tests/unit/file-cache.test.ts @@ -6,6 +6,7 @@ import fs from 'fs-extra'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import type { FileInfo } from '../../src/core/file-processor'; import { FileCache } from '../../src/utils/file-cache'; +import { normalizePath } from '../../src/utils/normalize-path'; describe('FileCache', () => { const TEST_DIR = path.join(os.tmpdir(), 'file-cache-test'); @@ -82,7 +83,7 @@ describe('FileCache', () => { }); it('should persist cache to disk and load it', async () => { - const testFile = path.join(TEST_DIR, 'persist.txt'); + const testFile = normalizePath(path.join(TEST_DIR, 'persist.txt')); await fs.writeFile(testFile, 'persist test'); const fileInfo: FileInfo = { @@ -102,7 +103,29 @@ describe('FileCache', () => { const newFileCache = new FileCache(CACHE_FILE); const retrieved = await newFileCache.get(testFile); - expect(retrieved).toEqual(fileInfo); + expect(retrieved).toBeDefined(); + expect(retrieved).not.toBeNull(); + + if (retrieved) { + expect(normalizePath(retrieved.path)).toEqual( + normalizePath(fileInfo.path), + ); + expect(retrieved.content).toEqual(fileInfo.content); + expect(retrieved.size).toEqual(fileInfo.size); + expect(retrieved.language).toEqual(fileInfo.language); + expect(retrieved.created).toBeInstanceOf(Date); + expect(retrieved.modified).toBeInstanceOf(Date); + expect(retrieved.created.getTime()).toBeCloseTo( + fileInfo.created.getTime(), + -3, + ); + expect(retrieved.modified.getTime()).toBeCloseTo( + fileInfo.modified.getTime(), + -3, + ); + } else { + throw new Error('Retrieved cache item is null'); + } }); it('should clear the cache', async () => {