/
read-file-or-url.ts
83 lines (78 loc) · 2.71 KB
/
read-file-or-url.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { fetchache, KeyValueCache, Request } from 'fetchache';
import isUrl from 'is-url';
import { load as loadYaml } from 'js-yaml';
import { isAbsolute, resolve } from 'path';
export { isUrl };
interface ReadFileOrUrlOptions extends RequestInit {
allowUnknownExtensions?: boolean;
fallbackFormat?: 'json' | 'yaml';
}
export async function readFileOrUrlWithCache<T>(
filePathOrUrl: string,
cache: KeyValueCache,
config?: ReadFileOrUrlOptions
): Promise<T> {
if (isUrl(filePathOrUrl)) {
return readUrlWithCache(filePathOrUrl, cache, config);
} else {
return readFileWithCache(filePathOrUrl, cache, config);
}
}
export async function readFileWithCache<T>(
filePath: string,
cache: KeyValueCache,
config?: ReadFileOrUrlOptions
): Promise<T> {
const { readFile, stat } = await import('fs-extra');
const actualPath = isAbsolute ? filePath : resolve(process.cwd(), filePath);
const cachedObjStr = await cache.get(actualPath);
const stats = await stat(actualPath);
if (cachedObjStr) {
const cachedObj = JSON.parse(cachedObjStr);
if (stats.mtimeMs <= cachedObj.mtimeMs) {
return cachedObj.result;
}
}
let result: any = await readFile(actualPath, 'utf-8');
if (/json$/.test(filePath)) {
result = JSON.parse(result);
} else if (/yaml$/.test(filePath) || /yml$/.test(filePath)) {
result = loadYaml(result);
} else if (config?.fallbackFormat) {
switch (config.fallbackFormat) {
case 'json':
result = JSON.parse(result);
break;
case 'yaml':
result = loadYaml(result);
break;
}
} else if (!config?.allowUnknownExtensions) {
throw new Error(
`Failed to parse JSON/YAML. Ensure file '${filePath}' has ` +
`the correct extension (i.e. '.json', '.yaml', or '.yml).`
);
}
cache.set(filePath, JSON.stringify({ result, mtimeMs: stats.mtimeMs }));
return result;
}
export async function readUrlWithCache<T>(
path: string,
cache: KeyValueCache,
config?: ReadFileOrUrlOptions
): Promise<T> {
const response = await fetchache(new Request(path, config), cache);
const contentType = response.headers?.get('content-type') || '';
const responseText = await response.text();
if (/json$/.test(path) || contentType.startsWith('application/json')) {
return JSON.parse(responseText);
} else if (/yaml$/.test(path) || /yml$/.test(path) || contentType.includes('yaml') || contentType.includes('yml')) {
return (loadYaml(responseText) as any) as T;
} else if (!config?.allowUnknownExtensions) {
throw new Error(
`Failed to parse JSON/YAML. Ensure URL '${path}' has ` +
`the correct extension (i.e. '.json', '.yaml', or '.yml) or mime type in the response headers.`
);
}
return responseText as any;
}