Skip to content

Commit 65a4e7f

Browse files
committed
feat(cache): refactor cache validation and storage
The cache validation and storage mechanism has been refactored. The `StoreData` interface and `isStoreData` function have been removed. The cache data is now directly read from the file and validated by checking if it ends with a specific hash comment. The cache data is stored along with this hash comment. The hash comment is generated using the `typia` version and the cache key. The tests have been updated to reflect these changes.
1 parent 1db02b5 commit 65a4e7f

File tree

2 files changed

+33
-34
lines changed

2 files changed

+33
-34
lines changed

packages/unplugin-typia/src/core/cache.ts

+16-31
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { accessSync, constants, existsSync, mkdirSync, readFileSync, rmSync, wri
22
import { createHash } from 'node:crypto';
33
import { basename, dirname, join } from 'pathe';
44
import type { Tagged } from 'type-fest';
5+
import { readPackageJSON } from 'pkg-types';
56
import type { transformTypia } from './typia.js';
67
import type { ResolvedOptions } from './options.js';
78
import { isBun } from './utils.js';
@@ -10,21 +11,8 @@ type ResolvedCacheOptions = ResolvedOptions['cache'];
1011

1112
type Data = Awaited<ReturnType<typeof transformTypia>>;
1213

13-
interface StoreData {
14-
data: NonNullable<Data>;
15-
source: string;
16-
}
17-
18-
function isStoreData(value: unknown): value is StoreData {
19-
if (typeof value !== 'object' || value === null) {
20-
return false;
21-
}
22-
const data = value as StoreData;
23-
return data.data != null
24-
&& typeof data.source === 'string';
25-
}
26-
2714
let cacheDir: string | null = null;
15+
let typiaVersion: string | undefined;
2816

2917
/**
3018
* Get cache
@@ -45,26 +33,17 @@ export async function getCache(
4533
const key = getKey(id, source);
4634
const path = getCachePath(key, option);
4735

48-
let data: StoreData | null = null;
4936
if (existsSync(path)) {
50-
const cache = readFileSync(path, 'utf8');
51-
const json = JSON.parse(cache);
52-
if (!isStoreData(json)) {
53-
return null;
54-
}
55-
data = json;
56-
}
37+
const data = readFileSync(path, 'utf8');
5738

58-
/** validate cache */
59-
if (!isStoreData(data)) {
60-
return null;
61-
}
39+
const hashComment = await getHashComment(key);
6240

63-
if (data.source !== source) {
64-
return null;
41+
if (data.endsWith(hashComment)) {
42+
return data;
43+
}
6544
}
6645

67-
return data.data;
46+
return null;
6847
}
6948

7049
/**
@@ -87,14 +66,15 @@ export async function setCache(
8766

8867
const key = getKey(id, source);
8968
const path = getCachePath(key, option);
69+
const hashComment = await getHashComment(key);
9070

9171
if (data == null) {
9272
rmSync(path);
9373
return;
9474
}
9575

96-
const json = JSON.stringify({ data, source });
97-
writeFileSync(path, json, { encoding: 'utf8' });
76+
const cache = data + hashComment;
77+
writeFileSync(path, cache, { encoding: 'utf8' });
9878
}
9979

10080
type CacheKey = Tagged<string, 'cache-key'>;
@@ -158,3 +138,8 @@ function hash(input: string): string {
158138
}
159139
return createHash('md5').update(input).digest('hex');
160140
}
141+
142+
export async function getHashComment(cachePath: CacheKey) {
143+
typiaVersion = typiaVersion ?? await readPackageJSON('typia').then(pkg => pkg.version);
144+
return `/* unplugin-typia-${typiaVersion ?? ''}-${cachePath} */`;
145+
}

packages/unplugin-typia/test/cache.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ type Data = Parameters<typeof cache.setCache>[2];
88

99
const tmp = tmpdir();
1010

11+
function removeComments(data: string | null) {
12+
if (data == null) {
13+
return data;
14+
}
15+
return data.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '');
16+
}
17+
1118
test('return null if cache is not found', async () => {
1219
const option = { enable: true, base: tmp } as const;
1320
const random = Math.random().toString();
@@ -27,7 +34,10 @@ test('set and get cache', async () => {
2734
/* get cache */
2835
const cacheData = await cache.getCache(filename, random, option);
2936

30-
assertEquals(cacheData, data);
37+
/* delete js asterisk comments */
38+
const cacheDataStr = removeComments(cacheData);
39+
40+
assertEquals(data, cacheDataStr);
3141
});
3242

3343
test('set and get null with different id', async () => {
@@ -40,9 +50,13 @@ test('set and get null with different id', async () => {
4050
await cache.setCache(filename, random, data, option);
4151

4252
/* get cache */
43-
const cacheData = await cache.getCache(`${random}-1`, random, option);
53+
const cacheData = await cache.getCache(`111;${random}`, random, option);
54+
55+
/* delete js asterisk comments */
56+
const cacheDataStr = removeComments(cacheData);
4457

45-
assertNotEquals(cacheData, data);
58+
assertEquals(cacheDataStr, null);
59+
assertNotEquals(data, cacheDataStr);
4660
});
4761

4862
test('set and get null with cache disabled', async () => {

0 commit comments

Comments
 (0)