/
package-cache.ts
90 lines (75 loc) · 2.66 KB
/
package-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
import Package from './package';
import { realpathSync } from 'fs';
import { getOrCreate } from './get-or-create';
import resolvePackagePath from 'resolve-package-path';
import { dirname } from 'path';
import { sync as pkgUpSync } from 'pkg-up';
export default class PackageCache {
resolve(packageName: string, fromPackage: Package): Package {
let cache = getOrCreate(this.resolutionCache, fromPackage, () => new Map());
return getOrCreate(cache, packageName, () => {
let root = dirname(resolvePackagePath(packageName, this.basedir(fromPackage)));
return this.getAddon(root);
});
}
getApp(packageRoot: string) {
return this.getPackage(packageRoot, false);
}
overridePackage(pkg: Package) {
this.rootCache.set(pkg.root, pkg);
}
overrideResolution(packageName: string, fromPackage: Package, answer: Package) {
this.rootCache.set(answer.root, answer);
let cache = getOrCreate(this.resolutionCache, fromPackage, () => new Map());
cache.set(packageName, answer);
}
protected rootCache: Map<string, Package> = new Map();
protected resolutionCache: Map<Package, Map<string, Package>> = new Map();
protected basedir(pkg: Package): string {
return pkg.root;
}
private getPackage(packageRoot: string, isAddon: boolean): Package {
let root = realpathSync(packageRoot);
let p = getOrCreate(this.rootCache, root, () => {
return new Package(root, !isAddon, this);
});
return p;
}
getAddon(packageRoot: string) {
return this.getPackage(packageRoot, true);
}
ownerOfFile(filename: string): Package | undefined {
let segments = filename.split('/');
// first we look through our cached packages for any that are rooted right
// at or above the file.
for (let length = segments.length - 1; length >= 0; length--) {
if (segments[length-1] === 'node_modules') {
// once we hit a node_modules, we're leaving the package we were in, so
// any higher caches don't apply to us
break;
}
let candidate = segments.slice(0, length).join('/');
if (this.rootCache.has(candidate)) {
return this.rootCache.get(candidate);
}
}
let packageJSONPath = pkgUpSync(filename);
if (packageJSONPath) {
return this.getAddon(dirname(packageJSONPath));
}
}
// register to be shared as the per-process package cache with the given name
shareAs(identifier: string) {
shared.set(identifier, this);
}
static shared(identifier: string) {
let p = shared.get(identifier);
if (p) {
return p;
}
p = new PackageCache();
shared.set(identifier,p);
return p;
}
}
const shared: Map<string, PackageCache> = new Map();