Skip to content

Commit c9b82ed

Browse files
committed
[in progress] project system work
1 parent 9763dc8 commit c9b82ed

9 files changed

Lines changed: 1139 additions & 1052 deletions

File tree

Jakefile.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ var servicesSources = [
101101

102102
var serverCoreSources = [
103103
"node.d.ts",
104+
"utilities.ts",
104105
"scriptVersionCache.ts",
106+
"scriptInfo.ts",
107+
"lsHost.ts",
108+
"project.ts",
105109
"editorServices.ts",
106110
"protocol.d.ts",
107111
"session.ts",

src/server/editorServices.ts

Lines changed: 227 additions & 982 deletions
Large diffs are not rendered by default.

src/server/lshost.ts

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/// <reference path="..\services\services.ts" />
2+
/// <reference path="utilities.ts" />
3+
/// <reference path="scriptInfo.ts" />
4+
5+
namespace ts.server {
6+
export class LSHost implements ts.LanguageServiceHost, ModuleResolutionHost, ServerLanguageServiceHost {
7+
private compilationSettings: ts.CompilerOptions;
8+
private readonly resolvedModuleNames: ts.FileMap<Map<ResolvedModuleWithFailedLookupLocations>>;
9+
private readonly resolvedTypeReferenceDirectives: ts.FileMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>;
10+
private readonly getCanonicalFileName: (fileName: string) => string;
11+
12+
constructor(private readonly host: ServerHost, private readonly project: Project, private readonly cancellationToken: HostCancellationToken) {
13+
this.getCanonicalFileName = ts.createGetCanonicalFileName(this.host.useCaseSensitiveFileNames);
14+
this.resolvedModuleNames = createFileMap<Map<ResolvedModuleWithFailedLookupLocations>>();
15+
this.resolvedTypeReferenceDirectives = createFileMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
16+
}
17+
18+
private resolveNamesWithLocalCache<T extends { failedLookupLocations: string[] }, R>(
19+
names: string[],
20+
containingFile: string,
21+
cache: ts.FileMap<Map<T>>,
22+
loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => T,
23+
getResult: (s: T) => R): R[] {
24+
25+
const path = toPath(containingFile, this.host.getCurrentDirectory(), this.getCanonicalFileName);
26+
const currentResolutionsInFile = cache.get(path);
27+
28+
const newResolutions: Map<T> = {};
29+
const resolvedModules: R[] = [];
30+
const compilerOptions = this.getCompilationSettings();
31+
32+
for (const name of names) {
33+
// check if this is a duplicate entry in the list
34+
let resolution = lookUp(newResolutions, name);
35+
if (!resolution) {
36+
const existingResolution = currentResolutionsInFile && ts.lookUp(currentResolutionsInFile, name);
37+
if (moduleResolutionIsValid(existingResolution)) {
38+
// ok, it is safe to use existing name resolution results
39+
resolution = existingResolution;
40+
}
41+
else {
42+
newResolutions[name] = resolution = loader(name, containingFile, compilerOptions, this);
43+
}
44+
}
45+
46+
ts.Debug.assert(resolution !== undefined);
47+
48+
resolvedModules.push(getResult(resolution));
49+
}
50+
51+
// replace old results with a new one
52+
cache.set(path, newResolutions);
53+
return resolvedModules;
54+
55+
function moduleResolutionIsValid(resolution: T): boolean {
56+
if (!resolution) {
57+
return false;
58+
}
59+
60+
if (getResult(resolution)) {
61+
// TODO: consider checking failedLookupLocations
62+
return true;
63+
}
64+
65+
// consider situation if we have no candidate locations as valid resolution.
66+
// after all there is no point to invalidate it if we have no idea where to look for the module.
67+
return resolution.failedLookupLocations.length === 0;
68+
}
69+
}
70+
71+
getProjectVersion() {
72+
return this.project.getProjectVersion();
73+
}
74+
75+
getCancellationToken() {
76+
return this.cancellationToken;
77+
}
78+
79+
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
80+
return this.resolveNamesWithLocalCache(typeDirectiveNames, containingFile, this.resolvedTypeReferenceDirectives, resolveTypeReferenceDirective, m => m.resolvedTypeReferenceDirective);
81+
}
82+
83+
resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModule[] {
84+
return this.resolveNamesWithLocalCache(moduleNames, containingFile, this.resolvedModuleNames, resolveModuleName, m => m.resolvedModule);
85+
}
86+
87+
getDefaultLibFileName() {
88+
const nodeModuleBinDir = ts.getDirectoryPath(ts.normalizePath(this.host.getExecutingFilePath()));
89+
return ts.combinePaths(nodeModuleBinDir, ts.getDefaultLibFileName(this.compilationSettings));
90+
}
91+
92+
getScriptSnapshot(filename: string): ts.IScriptSnapshot {
93+
const scriptInfo = this.project.getScriptInfo(filename);
94+
if (scriptInfo) {
95+
return scriptInfo.snap();
96+
}
97+
}
98+
99+
setCompilationSettings(opt: ts.CompilerOptions) {
100+
this.compilationSettings = opt;
101+
// conservatively assume that changing compiler options might affect module resolution strategy
102+
this.resolvedModuleNames.clear();
103+
this.resolvedTypeReferenceDirectives.clear();
104+
}
105+
106+
getCompilationSettings() {
107+
// change this to return active project settings for file
108+
return this.compilationSettings;
109+
}
110+
111+
getScriptFileNames() {
112+
return this.project.getRootFiles();
113+
}
114+
115+
getScriptKind(fileName: string) {
116+
const info = this.project.getScriptInfo(fileName);
117+
return info && info.scriptKind;
118+
}
119+
120+
getScriptVersion(filename: string) {
121+
return this.project.getScriptInfo(filename).getLatestVersion();
122+
}
123+
124+
getCurrentDirectory(): string {
125+
return "";
126+
}
127+
128+
removeReferencedFile(info: ScriptInfo) {
129+
if (!info.isOpen) {
130+
this.resolvedModuleNames.remove(info.path);
131+
this.resolvedTypeReferenceDirectives.remove(info.path);
132+
}
133+
}
134+
135+
removeRoot(info: ScriptInfo) {
136+
this.resolvedModuleNames.remove(info.path);
137+
this.resolvedTypeReferenceDirectives.remove(info.path);
138+
}
139+
140+
resolvePath(path: string): string {
141+
return this.host.resolvePath(path);
142+
}
143+
144+
fileExists(path: string): boolean {
145+
return this.host.fileExists(path);
146+
}
147+
148+
directoryExists(path: string): boolean {
149+
return this.host.directoryExists(path);
150+
}
151+
152+
readFile(fileName: string): string {
153+
return this.host.readFile(fileName);
154+
}
155+
156+
getDirectories(path: string): string[] {
157+
return this.host.getDirectories(path);
158+
}
159+
}
160+
}

0 commit comments

Comments
 (0)