forked from microsoft/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtypingsCache.ts
More file actions
128 lines (112 loc) · 5.03 KB
/
typingsCache.ts
File metadata and controls
128 lines (112 loc) · 5.03 KB
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/// <reference path="project.ts"/>
namespace ts.server {
export interface ITypingsInstaller {
enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>): void;
attach(projectService: ProjectService): void;
onProjectClosed(p: Project): void;
readonly globalTypingsCacheLocation: string;
}
export const nullTypingsInstaller: ITypingsInstaller = {
enqueueInstallTypingsRequest: noop,
attach: noop,
onProjectClosed: noop,
globalTypingsCacheLocation: undefined
};
class TypingsCacheEntry {
readonly typeAcquisition: TypeAcquisition;
readonly compilerOptions: CompilerOptions;
readonly typings: SortedReadonlyArray<string>;
readonly unresolvedImports: SortedReadonlyArray<string>;
/* mainly useful for debugging */
poisoned: boolean;
}
function setIsEqualTo(arr1: string[], arr2: string[]): boolean {
if (arr1 === arr2) {
return true;
}
if ((arr1 || emptyArray).length === 0 && (arr2 || emptyArray).length === 0) {
return true;
}
const set: Map<boolean> = createMap<boolean>();
let unique = 0;
for (const v of arr1) {
if (set.get(v) !== true) {
set.set(v, true);
unique++;
}
}
for (const v of arr2) {
const isSet = set.get(v);
if (isSet === undefined) {
return false;
}
if (isSet === true) {
set.set(v, false);
unique--;
}
}
return unique === 0;
}
function typeAcquisitionChanged(opt1: TypeAcquisition, opt2: TypeAcquisition): boolean {
return opt1.enable !== opt2.enable ||
!setIsEqualTo(opt1.include, opt2.include) ||
!setIsEqualTo(opt1.exclude, opt2.exclude);
}
function compilerOptionsChanged(opt1: CompilerOptions, opt2: CompilerOptions): boolean {
// TODO: add more relevant properties
return opt1.allowJs !== opt2.allowJs;
}
function unresolvedImportsChanged(imports1: SortedReadonlyArray<string>, imports2: SortedReadonlyArray<string>): boolean {
if (imports1 === imports2) {
return false;
}
return !arrayIsEqualTo(imports1, imports2);
}
export class TypingsCache {
private readonly perProjectCache: Map<TypingsCacheEntry> = createMap<TypingsCacheEntry>();
constructor(private readonly installer: ITypingsInstaller) {
}
getTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray<string>, forceRefresh: boolean): SortedReadonlyArray<string> {
const typeAcquisition = project.getTypeAcquisition();
if (!typeAcquisition || !typeAcquisition.enable) {
return <any>emptyArray;
}
const entry = this.perProjectCache.get(project.getProjectName());
const result: SortedReadonlyArray<string> = entry ? entry.typings : <any>emptyArray;
if (forceRefresh ||
!entry ||
typeAcquisitionChanged(typeAcquisition, entry.typeAcquisition) ||
compilerOptionsChanged(project.getCompilerOptions(), entry.compilerOptions) ||
unresolvedImportsChanged(unresolvedImports, entry.unresolvedImports)) {
// Note: entry is now poisoned since it does not really contain typings for a given combination of compiler options\typings options.
// instead it acts as a placeholder to prevent issuing multiple requests
this.perProjectCache.set(project.getProjectName(), {
compilerOptions: project.getCompilerOptions(),
typeAcquisition,
typings: result,
unresolvedImports,
poisoned: true
});
// something has been changed, issue a request to update typings
this.installer.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports);
}
return result;
}
updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string>, newTypings: string[]) {
this.perProjectCache.set(projectName, {
compilerOptions,
typeAcquisition,
typings: toSortedArray(newTypings),
unresolvedImports,
poisoned: false
});
}
deleteTypingsForProject(projectName: string) {
this.perProjectCache.delete(projectName);
}
onProjectClosed(project: Project) {
this.perProjectCache.delete(project.getProjectName());
this.installer.onProjectClosed(project);
}
}
}