-
Notifications
You must be signed in to change notification settings - Fork 12k
/
Copy pathload-result-cache.ts
91 lines (76 loc) · 2.63 KB
/
load-result-cache.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
84
85
86
87
88
89
90
91
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import type { OnLoadResult, PluginBuild } from 'esbuild';
import { normalize } from 'node:path';
export interface LoadResultCache {
get(path: string): OnLoadResult | undefined;
put(path: string, result: OnLoadResult): Promise<void>;
readonly watchFiles: ReadonlyArray<string>;
}
export function createCachedLoad(
cache: LoadResultCache | undefined,
callback: Parameters<PluginBuild['onLoad']>[1],
): Parameters<PluginBuild['onLoad']>[1] {
if (cache === undefined) {
return callback;
}
return async (args) => {
const loadCacheKey = `${args.namespace}:${args.path}`;
let result: OnLoadResult | null | undefined = cache.get(loadCacheKey);
if (result === undefined) {
result = await callback(args);
// Do not cache null or undefined
if (result) {
// Ensure requested path is included if it was a resolved file
if (args.namespace === 'file') {
result.watchFiles ??= [];
result.watchFiles.push(args.path);
}
await cache.put(loadCacheKey, result);
}
}
return result;
};
}
export class MemoryLoadResultCache implements LoadResultCache {
#loadResults = new Map<string, OnLoadResult>();
#fileDependencies = new Map<string, Set<string>>();
get(path: string): OnLoadResult | undefined {
return this.#loadResults.get(path);
}
async put(path: string, result: OnLoadResult): Promise<void> {
this.#loadResults.set(path, result);
if (result.watchFiles) {
for (const watchFile of result.watchFiles) {
// Normalize the watch file path to ensure OS consistent paths
const normalizedWatchFile = normalize(watchFile);
let affected = this.#fileDependencies.get(normalizedWatchFile);
if (affected === undefined) {
affected = new Set();
this.#fileDependencies.set(normalizedWatchFile, affected);
}
affected.add(path);
}
}
}
invalidate(path: string): boolean {
const affected = this.#fileDependencies.get(path);
let found = false;
if (affected) {
affected.forEach((a) => (found ||= this.#loadResults.delete(a)));
this.#fileDependencies.delete(path);
}
found ||= this.#loadResults.delete(path);
return found;
}
get watchFiles(): string[] {
// this.#loadResults.keys() is not included here because the keys
// are namespaced request paths and not disk-based file paths.
return [...this.#fileDependencies.keys()];
}
}