Skip to content
This repository was archived by the owner on Dec 1, 2019. It is now read-only.

Commit 799b17c

Browse files
committed
feat: resolve type reference directives
1 parent 9222dc4 commit 799b17c

File tree

5 files changed

+95
-68
lines changed

5 files changed

+95
-68
lines changed

src/checker-runtime.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ export interface IInitPayload {
2525

2626
export interface ICompilePayload {
2727
files: {[fileName: string]: IFile};
28-
resolutionCache: {[fileName: string]: ts.ResolvedModule};
28+
moduleResolutionCache: {[fileName: string]: ts.ResolvedModule};
29+
typeReferenceResolutionCache: {[fileName: string]: ts.ResolvedTypeReferenceDirective};
2930
}
3031

3132
export interface IEnv {
@@ -36,7 +37,8 @@ export interface IEnv {
3637
compilerInfo?: ICompilerInfo;
3738
host?: Host;
3839
files?: {[fileName: string]: IFile};
39-
resolutionCache?: {[fileName: string]: ts.ResolvedModule};
40+
moduleResolutionCache?: {[fileName: string]: ts.ResolvedModule};
41+
typeReferenceResolutionCache?: {[fileName: string]: ts.ResolvedTypeReferenceDirective};
4042
program?: ts.Program;
4143
service?: ts.LanguageService;
4244
plugins?: LoaderPluginDef[];
@@ -111,9 +113,16 @@ export class Host implements ts.LanguageServiceHost {
111113
return env.compilerOptions;
112114
}
113115

116+
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string) {
117+
return typeDirectiveNames.map(moduleName => {
118+
console.log('resolve type ref', containingFile, typeDirectiveNames, env.typeReferenceResolutionCache[`${containingFile}::${moduleName}`]);
119+
return env.typeReferenceResolutionCache[`${containingFile}::${moduleName}`];
120+
});
121+
}
122+
114123
resolveModuleNames(moduleNames: string[], containingFile: string) {
115124
return moduleNames.map(moduleName => {
116-
return env.resolutionCache[`${containingFile}::${moduleName}`];
125+
return env.moduleResolutionCache[`${containingFile}::${moduleName}`];
117126
});
118127
}
119128

@@ -159,7 +168,8 @@ function processCompile(payload: ICompilePayload) {
159168
});
160169

161170
env.files = payload.files;
162-
env.resolutionCache = payload.resolutionCache;
171+
env.moduleResolutionCache = payload.moduleResolutionCache;
172+
env.typeReferenceResolutionCache = payload.typeReferenceResolutionCache;
163173

164174
let program = env.program = env.service.getProgram();
165175

src/deps.ts

+61-56
Original file line numberDiff line numberDiff line change
@@ -58,49 +58,59 @@ export class FileAnalyzer {
5858

5959
imports.forEach(imp => {
6060
this.dependencies.addDependency(fileName, imp);
61-
this.checkDependencies(imp.resolvedFileName);
61+
this.checkDependencies(imp);
6262
});
6363

6464
return null;
6565
}
6666

67-
findImportDeclarations(fileName: string): ts.ResolvedModule[] {
67+
findImportDeclarations(fileName: string) {
6868
let sourceFile = this.state.getSourceFile(fileName);
6969
let isJavaScript = sourceFile.flags & this.state.ts.NodeFlags.JavaScriptFile;
7070
let info = this.state.ts.preProcessFile(sourceFile.text, true, !!isJavaScript);
71+
let options = this.state.compilerConfig.options;
72+
let ts = this.state.ts;
73+
let deps = this.state.fileAnalyzer.dependencies;
7174

72-
return info.importedFiles
73-
.map(file => file.fileName)
74-
.map(depName => this.resolve(fileName, depName))
75-
.filter(Boolean);
76-
}
77-
78-
resolve(fileName: string, depName: string): ts.ResolvedModule {
75+
let imports: string[] = [];
7976

80-
if (/^[a-z0-9].*\.d\.ts$/.test(depName)) {
81-
// Make import relative
82-
// We need this to be able to resolve directives like
83-
//
84-
// <reference path="lib.d.ts" />
85-
//
86-
// with resolver.
87-
depName = './' + depName;
88-
}
89-
90-
let resolution = this.state.ts.resolveModuleName(
91-
depName,
92-
fileName,
93-
this.state.compilerConfig.options,
94-
this.state.ts.sys
95-
);
77+
imports.push.apply(imports, info.importedFiles
78+
.map(file => file.fileName)
79+
.map(depName => {
80+
let { resolvedModule } = ts.resolveModuleName(depName, fileName, options, ts.sys);
81+
if (resolvedModule) {
82+
deps.addModuleResolution(fileName, depName, resolvedModule);
83+
return resolvedModule.resolvedFileName;
84+
}
85+
})
86+
.filter(Boolean));
9687

97-
let { resolvedModule } = resolution;
88+
imports.push.apply(imports, info.referencedFiles
89+
.map(file => file.fileName)
90+
.map(depName => {
91+
return /^[a-z0-9].*\.d\.ts$/.test(depName) ? './' + depName : depName;
92+
})
93+
.map(depName => {
94+
let { resolvedModule } = ts.resolveModuleName(depName, fileName, options, ts.sys);
95+
if (resolvedModule) {
96+
deps.addModuleResolution(fileName, depName, resolvedModule);
97+
return resolvedModule.resolvedFileName;
98+
}
99+
})
100+
.filter(Boolean));
98101

99-
if (resolvedModule) {
100-
this.state.fileAnalyzer.dependencies.addResolution(fileName, depName, resolvedModule);
101-
}
102+
imports.push.apply(imports, info.typeReferenceDirectives
103+
.map(file => file.fileName)
104+
.map(depName => {
105+
let { resolvedTypeReferenceDirective } = ts.resolveTypeReferenceDirective(depName, fileName, options, ts.sys);
106+
if (resolvedTypeReferenceDirective) {
107+
deps.addTypeReferenceResolution(fileName, depName, resolvedTypeReferenceDirective);
108+
return resolvedTypeReferenceDirective.resolvedFileName;
109+
}
110+
})
111+
.filter(Boolean));
102112

103-
return resolvedModule;
113+
return imports;
104114
}
105115
}
106116

@@ -110,27 +120,35 @@ export interface IDependencyGraphItem {
110120
}
111121

112122
export class DependencyManager {
113-
dependencies: {[fileName: string]: ts.ResolvedModule[]};
114-
resolutions: {[cacheKey: string]: ts.ResolvedModule};
115-
knownTypeDeclarations: FileSet;
123+
dependencies: {[fileName: string]: string[]};
124+
moduleResolutions: {[cacheKey: string]: ts.ResolvedModule};
125+
typeReferenceResolutions: {[cacheKey: string]: ts.ResolvedTypeReferenceDirective};
116126
compiledModules: {[fileName: string]: string[]};
117127

118128
constructor() {
119129
this.dependencies = {};
120-
this.knownTypeDeclarations = {};
121130
this.compiledModules = {};
122-
this.resolutions = {};
131+
this.moduleResolutions = {};
132+
this.typeReferenceResolutions = {};
133+
}
134+
135+
addModuleResolution(fileName: string, depName: string, resolvedModule: ts.ResolvedModule) {
136+
this.moduleResolutions[`${fileName}::${depName}`] = resolvedModule;
123137
}
124138

125-
addResolution(fileName: string, depName: string, resolvedModule: ts.ResolvedModule) {
126-
this.resolutions[`${fileName}::${depName}`] = resolvedModule;
139+
addTypeReferenceResolution(fileName: string, depName: string, resolvedModule: ts.ResolvedTypeReferenceDirective) {
140+
this.typeReferenceResolutions[`${fileName}::${depName}`] = resolvedModule;
127141
}
128142

129-
getResolution(fileName: string, depName: string): ts.ResolvedModule {
130-
return this.resolutions[`${fileName}::${depName}`];
143+
getModuleResolution(fileName: string, depName: string): ts.ResolvedModule {
144+
return this.moduleResolutions[`${fileName}::${depName}`];
131145
}
132146

133-
addDependency(fileName: string, dep: ts.ResolvedModule): void {
147+
getTypeReferenceResolution(fileName: string, depName: string): ts.ResolvedTypeReferenceDirective {
148+
return this.typeReferenceResolutions[`${fileName}::${depName}`];
149+
}
150+
151+
addDependency(fileName: string, dep: string): void {
134152
if (!this.dependencies.hasOwnProperty(fileName)) {
135153
this.clearDependencies(fileName);
136154
}
@@ -158,26 +176,14 @@ export class DependencyManager {
158176
this.compiledModules[fileName] = [];
159177
}
160178

161-
getDependencies(fileName: string): ts.ResolvedModule[] {
179+
getDependencies(fileName: string): string[] {
162180
if (!this.dependencies.hasOwnProperty(fileName)) {
163181
this.clearDependencies(fileName);
164182
}
165183

166184
return this.dependencies[fileName].slice();
167185
}
168186

169-
addTypeDeclaration(fileName: string) {
170-
this.knownTypeDeclarations[fileName] = true;
171-
}
172-
173-
hasTypeDeclaration(fileName: string): boolean {
174-
return this.knownTypeDeclarations.hasOwnProperty(fileName);
175-
}
176-
177-
getTypeDeclarations(): {[fileName: string]: boolean} {
178-
return objectAssign({}, this.knownTypeDeclarations);
179-
}
180-
181187
getDependencyGraph(fileName: string): IDependencyGraphItem {
182188
let appliedDeps: {[fileName: string]: boolean} = {};
183189
let result: IDependencyGraphItem = {
@@ -186,10 +192,9 @@ export class DependencyManager {
186192
};
187193

188194
let walk = (fileName: string, context: IDependencyGraphItem) => {
189-
this.getDependencies(fileName).forEach((dep) => {
190-
let fileName = dep.resolvedFileName;
195+
this.getDependencies(fileName).forEach((depFileName) => {
191196
let depContext = {
192-
fileName: dep.resolvedFileName,
197+
fileName: depFileName,
193198
dependencies: []
194199
};
195200
context.dependencies.push(depContext);

src/host.ts

+15-5
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,18 @@ export class Host implements ts.LanguageServiceHost {
7171
return this.state.defaultLib;
7272
}
7373

74-
resolveModuleNames(moduleNames: string[], containingFile: string) {
75-
let resolutions = moduleNames.map(moduleName => {
76-
return this.state.fileAnalyzer.dependencies.getResolution(containingFile, moduleName);
74+
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string) {
75+
let deps = this.state.fileAnalyzer.dependencies;
76+
return typeDirectiveNames.map(moduleName => {
77+
return deps.getTypeReferenceResolution(containingFile, moduleName);
7778
});
79+
}
7880

79-
return resolutions;
81+
resolveModuleNames(moduleNames: string[], containingFile: string) {
82+
let deps = this.state.fileAnalyzer.dependencies;
83+
return moduleNames.map(moduleName => {
84+
return deps.getModuleResolution(containingFile, moduleName);
85+
});
8086
}
8187

8288
getDefaultLibLocation(): string {
@@ -188,7 +194,11 @@ export class State {
188194

189195
let source = this.program.getSourceFile(fileName);
190196
if (!source) {
191-
throw new Error(`File ${fileName} was not found in program`);
197+
this.updateProgram();
198+
source = this.program.getSourceFile(fileName);
199+
if (!source) {
200+
throw new Error(`File ${fileName} was not found in program`);
201+
}
192202
}
193203

194204
let emitResult = this.program.emit(source, writeFile);

src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function compiler(webpack: IWebPack, text: string): void {
5454
}
5555
});
5656

57-
invokeKnownFilesTime(instance);
57+
invokeKnownFilesOneTime(instance);
5858

5959
instance.compiledFiles[fileName] = true;
6060
let doUpdate = false;
@@ -201,7 +201,7 @@ function transform(webpack: IWebPack, instance: ICompilerInstance, fileName: str
201201
};
202202
}
203203

204-
function invokeKnownFilesTime(instance: ICompilerInstance) {
204+
function invokeKnownFilesOneTime(instance: ICompilerInstance) {
205205
if (instance.loaderConfig.externals && !instance.externalsInvoked) {
206206
instance.loaderConfig.externals
207207
.filter(isTypeDeclaration)

src/instance.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,13 @@ function setupAfterCompile(compiler, instanceName, forkChecker = false) {
365365

366366
let instance: ICompilerInstance = resolveInstance(compilation.compiler, instanceName);
367367
let state = instance.tsState;
368+
let deps = state.fileAnalyzer.dependencies;
368369

369370
if (forkChecker) {
370371
let payload = {
371372
files: state.allFiles(),
372-
resolutionCache: state.fileAnalyzer.dependencies.resolutions
373+
moduleResolutionCache: deps.moduleResolutions,
374+
typeReferenceResolutionCache: deps.typeReferenceResolutions
373375
};
374376

375377
runChecker(instance, payload);

0 commit comments

Comments
 (0)