8000 Improvements to tsc --watch by sheetalkamat · Pull Request #17669 · microsoft/TypeScript · GitHub
[go: up one dir, main page]

Skip to content

Improvements to tsc --watch #17669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Aug 31, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
802e283
Refactoring of the builder
sheetalkamat Jul 19, 2017
499fabc
Do not update graph in builder if compile on save is not on
sheetalkamat Jul 19, 2017
273569f
Make the host cache store the fileName instead of undefined for the m…
sheetalkamat Jul 19, 2017
94a589b
Program cannot be reused if the missing file is now present
sheetalkamat Jul 21, 2017
ef5935b
Initial refactoring so that watch from tsc follows the tsserver projects
sheetalkamat Jul 24, 2017
e068475
Refactor so that builder handles only source files and program
sheetalkamat Jul 24, 2017
6237b22
Move the builder to compiler directory
sheetalkamat Jul 24, 2017
9b18f7b
Use builder to emit the files from the tsc.js
sheetalkamat Jul 24, 2017
85b9254
Refactor out the tsc logic into another file so we can use that to te…
sheetalkamat Jul 26, 2017
69e5abd
Refactor watched system from tsserver tests so that tscLib watch can …
sheetalkamat Jul 26, 2017
c814d8e
Add tests for the tsc --watch
sheetalkamat Jul 26, 2017
2dd6aed
Emit tests
sheetalkamat Jul 29, 2017
89c61e7
Modify the api in builder so that it tracks changed files
sheetalkamat Aug 3, 2017
bb91b32
Add tests to verify emitted files
sheetalkamat Aug 3, 2017
46e3d1c
Refactoring so that instead of just using from tsc --watch the new ap…
sheetalkamat Aug 4, 2017
031a637
Switch back to have tsc.ts the only file thats different in tsc.js ge…
sheetalkamat Aug 4, 2017
0d5e6c9
Use cache for module resolution even in watch mode
sheetalkamat Aug 4, 2017
2762232
Test for the module resolution caching
sheetalkamat Aug 4, 2017
65a6ee0
Add test that fails because we dont watch module resolutions failed p…
sheetalkamat Aug 5, 2017
d55150c
Implementation of watching the failed lookup locations
sheetalkamat Aug 5, 2017
8dc6248
Partial implementation for invalidating the program (instead of sourc…
sheetalkamat Aug 5, 2017
7474ba7
Implementation for invalidating source file containing possibly chang…
sheetalkamat Aug 5, 2017
6385f7e
Get semantic diagnostics for the program from builder so that it cach…
sheetalkamat Aug 7, 2017
d0a23bb
Merge branch 'watchImprovements' into builder
sheetalkamat Aug 12, 2017
59d07dc
Simplified mutate map options
sheetalkamat Aug 14, 2017
9895082
Updating according to feedback from PR
sheetalkamat Aug 14, 2017
f1b1b12
More work based on feedback
sheetalkamat Aug 14, 2017
136b091
Update based on feedback
sheetalkamat Aug 14, 2017
6bf9133
Update to PR feedback
sheetalkamat Aug 14, 2017
a99c04e
Make the failedLookuplocations to be readonly array
sheetalkamat Aug 14, 2017
b66b752
Update based on feedback
sheetalkamat Aug 18, 2017
e639ceb
Merge branch 'watchImprovements' into builder
sheetalkamat Aug 18, 2017
8deef58
Remove the unused function from the Project since builder has this lo…
sheetalkamat Aug 18, 2017
60e2e68
Merge branch 'watchImprovements' into builder
sheetalkamat Aug 18, 2017
3908325
Merge branch 'watchImprovements' into builder
sheetalkamat Aug 21, 2017
7173da2
Adding test for #16329 to verify the caching of file system when open…
sheetalkamat Aug 18, 2017
e500be2
Adding test for #16456 to verify watched directories in case-sensitiv…
sheetalkamat Aug 19, 2017
6227a36
In Server when polling the file stat's do not send changed event in c…
sheetalkamat Aug 21, 2017
55931c4
Update the failed lookup watches without doing lookups.
sheetalkamat Aug 21, 2017
e65df12
Add test for #16955 which simulates npm install
sheetalkamat Aug 22, 2017
e711238
Add api in builder to get changed files and use it to send project ch…
sheetalkamat Aug 15, 2017
3b85f3f
Add tests to verify project changed event sent
sheetalkamat Aug 22, 2017
ea95f3b
Merge pull request #17820 from Microsoft/tsserverEventChangedFiles
sheetalkamat Aug 31, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Implementation for invalidating source file containing possibly chang…
…ed module resolution
  • Loading branch information
sheetalkamat committed Aug 7, 2017
commit 7474ba762cadf7aa20d9ffa6fccc3420ad79942c
18 changes: 8 additions & 10 deletions src/compiler/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace ts {
/**
* This is the callback when file infos in the builder are updated
*/
onProgramUpdateGraph(program: Program): void;
onProgramUpdateGraph(program: Program, hasInvalidatedResolution: HasInvalidatedResolution): void;
getFilesAffectedBy(program: Program, path: Path): string[];
emitFile(program: Program, path: Path): EmitOutput;
emitChangedFiles(program: Program): EmitOutputDetailed[];
Expand Down Expand Up @@ -84,7 +84,7 @@ namespace ts {
clear
};

function createProgramGraph(program: Program) {
function createProgramGraph(program: Program, hasInvalidatedResolution: HasInvalidatedResolution) {
const currentIsModuleEmit = program.getCompilerOptions().module !== ModuleKind.None;
if (isModuleEmit !== currentIsModuleEmit) {
isModuleEmit = currentIsModuleEmit;
Expand All @@ -100,7 +100,7 @@ namespace ts {
// Remove existing file info
removeExistingFileInfo,
// We will update in place instead of deleting existing value and adding new one
(existingInfo, sourceFile) => updateExistingFileInfo(program, existingInfo, sourceFile)
(existingInfo, sourceFile) => updateExistingFileInfo(program, existingInfo, sourceFile, hasInvalidatedResolution)
);
}

Expand All @@ -115,8 +115,8 @@ namespace ts {
emitHandler.removeScriptInfo(path);
}

function updateExistingFileInfo(program: Program, existingInfo: FileInfo, sourceFile: SourceFile) {
if (existingInfo.version !== sourceFile.version) {
function updateExistingFileInfo(program: Program, existingInfo: FileInfo, sourceFile: SourceFile, hasInvalidatedResolution: HasInvalidatedResolution) {
if (existingInfo.version !== sourceFile.version || hasInvalidatedResolution(sourceFile.path)) {
changedFilesSinceLastEmit.set(sourceFile.path, true);
existingInfo.version = sourceFile.version;
emitHandler.updateScriptInfo(program, sourceFile);
Expand All @@ -125,13 +125,13 @@ namespace ts {

function ensureProgramGraph(program: Program) {
if (!emitHandler) {
createProgramGraph(program);
createProgramGraph(program, noop);
}
}

function onProgramUpdateGraph(program: Program) {
function onProgramUpdateGraph(program: Program, hasInvalidatedResolution: HasInvalidatedResolution) {
if (emitHandler) {
createProgramGraph(program);
createProgramGraph(program, hasInvalidatedResolution);
}
}

Expand Down Expand Up @@ -298,8 +298,6 @@ namespace ts {
return result;
}

function noop() { }

function getNonModuleEmitHandler(): EmitHandler {
return {
addScriptInfo: noop,
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,7 @@ namespace ts {
}

/** Does nothing. */
export function noop(): void {}
export function noop(): any {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using any. Use () => false if you need a function that always returns a falsy value.


/** Throws an error because a function is not implemented. */
export function notImplemented(): never {
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/moduleNameResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,8 @@ namespace ts {
return !host.directoryExists || host.directoryExists(directoryName);
}

export type HasInvalidatedResolution = (sourceFile: Path) => boolean;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this type belongs in this file if it isn't used here.


/**
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
Expand Down
19 changes: 13 additions & 6 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ namespace ts {
}

export function isProgramUptoDate(program: Program, rootFileNames: string[], newOptions: CompilerOptions,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this function belongs here since it isn't used in this file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This belongs here because we want this as an api

getSourceVersion: (path: Path) => string, fileExists: (fileName: string) => boolean): boolean {
getSourceVersion: (path: Path) => string, fileExists: (fileName: string) => boolean, hasInvalidatedResolution: HasInvalidatedResolution): boolean {
// If we haven't create a program yet, then it is not up-to-date
if (!program) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: type should be Program | undefined

return false;
Expand Down Expand Up @@ -432,10 +432,9 @@ namespace ts {
return true;

function sourceFileUpToDate(sourceFile: SourceFile): boolean {
if (!sourceFile) {
return false;
}
return sourceFile.version === getSourceVersion(sourceFile.path);
return sourceFile &&
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: input type should be SourceFile | undefined

sourceFile.version === getSourceVersion(sourceFile.path) &&
!hasInvalidatedResolution(sourceFile.path);
}
}

Expand Down Expand Up @@ -565,6 +564,7 @@ namespace ts {

let moduleResolutionCache: ModuleResolutionCache;
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[];
const hasInvalidatedResolution = host.hasInvalidatedResolution || noop;
if (host.resolveModuleNames) {
resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(checkAllDefined(moduleNames), containingFile).map(resolved => {
// An older host may have omitted extension, in which case we should infer it from the file extension of resolvedFileName.
Expand Down Expand Up @@ -803,7 +803,7 @@ namespace ts {
trace(host, Diagnostics.Module_0_was_resolved_as_locally_declared_ambient_module_in_file_1, moduleName, containingFile);
}
}
else {
else if (!hasInvalidatedResolution(oldProgramState.file.path)) {
resolvesToAmbientModuleInNonModifiedFile = moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName, oldProgramState);
}

Expand Down Expand Up @@ -962,6 +962,13 @@ namespace ts {
// tentatively approve the file
modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
}
else if (hasInvalidatedResolution(oldSourceFile.path)) {
// 'module/types' references could have changed
oldProgram.structureIsReused = StructureIsReused.SafeModules;

// add file to the modified list so that we will resolve it later
modifiedSourceFiles.push({ oldFile: oldSourceFile, newFile: newSourceFile });
}

// if file has passed all checks it should be safe to reuse it
newSourceFiles.push(newSourceFile);
Expand Down
24 changes: 19 additions & 5 deletions src/compiler/resolutionCache.ts
10000
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
namespace ts {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this relate to the caching already in moduleNameResolver.ts?

export interface ResolutionCache {
setModuleResolutionHost(host: ModuleResolutionHost): void;

startRecordingFilesWithChangedResolutions(): void;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of two separate functions, how about recordFilesWithChangedResolutions(action: () => void): Path[];?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not having to create lambdas seem better option.

finishRecordingFilesWithChangedResolutions(): Path[];

resolveModuleNames(moduleNames: string[], containingFile: string, logChanges: boolean): ResolvedModuleFull[];
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];

invalidateResolutionOfDeletedFile(filePath: Path): void;
invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation: string): void;

createHasInvalidatedResolution(): HasInvalidatedResolution;

clear(): void;
}

Expand Down Expand Up @@ -40,6 +46,7 @@ namespace ts {

let host: ModuleResolutionHost;
let filesWithChangedSetOfUnresolvedImports: Path[];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

| undefined, same for below

let filesWithInvalidatedResolutions: Map<true>;

const resolvedModuleNames = createMap<Map<ResolvedModuleWithFailedLookupLocations>>();
const resolvedTypeReferenceDirectives = createMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
Expand All @@ -55,6 +62,7 @@ namespace ts {
resolveTypeReferenceDirectives,
invalidateResolutionOfDeletedFile,
invalidateResolutionOfChangedFailedLookupLocation,
createHasInvalidatedResolution,
clear
};

Expand Down Expand Up @@ -82,6 +90,12 @@ namespace ts {
return collected;
}

function createHasInvalidatedResolution(): HasInvalidatedResolution {
const collected = filesWithInvalidatedResolutions;
filesWithInvalidatedResolutions = undefined;
return path => collected && collected.has(path);
}

function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
const primaryResult = ts.resolveModuleName(moduleName, containingFile, compilerOptions, host);
// return result immediately only if it is .ts, .tsx or .d.ts
Expand Down Expand Up @@ -250,7 +264,7 @@ namespace ts {
cache: Map<Map<T>>,
getResult: (s: T) => R,
getResultFileName: (result: R) => string | undefined) {
cache.forEach((value, path) => {
cache.forEach((value, path: Path) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

if (path === deletedFilePath) {
cache.delete(path);
value.forEach((resolution, name) => {
Expand All @@ -264,6 +278,7 @@ namespace ts {
if (result) {
if (getResultFileName(result) === deletedFilePath) {
resolution.isInvalidated = true;
(filesWithInvalidatedResolutions || (filesWithInvalidatedResolutions = createMap<true>())).set(path, true);
}
}
}
Expand All @@ -275,14 +290,13 @@ namespace ts {
function invalidateResolutionCacheOfChangedFailedLookupLocation<T extends NameResolutionWithFailedLookupLocations>(
failedLookupLocation: string,
cache: Map<Map<T>>) {
cache.forEach((value, _containingFilePath) => {
cache.forEach((value, containingFile: Path) => {
if (value) {
value.forEach((resolution, __name) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

if (resolution && !resolution.isInvalidated && contains(resolution.failedLookupLocations, failedLookupLocation)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should 10000 failedLookupLocations be a Path[]?

// TODO: mark the file as needing re-evaluation of module resolution instead of using it blindly.
// Note: Right now this invalidation path is not used at all as it doesnt matter as we are anyways clearing the program,
// which means all the resolutions will be discarded.
// Mark the file as needing re-evaluation of module resolution instead of using it blindly.
resolution.isInvalidated = true;
(filesWithInvalidatedResolutions || (filesWithInvalidatedResolutions = createMap<true>())).set(containingFile, true);
}
});
}
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3979,6 +3979,7 @@ namespace ts {
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
getEnvironmentVariable?(name: string): string;
onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions): void;
hasInvalidatedResolution?: HasInvalidatedResolution;
}

/* @internal */
Expand Down
17 changes: 7 additions & 10 deletions src/compiler/watchedProgram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ namespace ts {

const sourceFilesCache = createMap<HostFileInfo | string>(); // Cache that stores the source file and version info
let missingFilePathsRequestedForRelease: Path[]; // These paths are held temparirly so that we can remove the entry from source file cache if the file is not tracked by missing files
let hasInvalidatedResolution: HasInvalidatedResolution; // Passed along to see if source file has invalidated resolutions

watchingHost = watchingHost || createWatchingSystemHost(compilerOptions.pretty);
const { system, parseConfigFile, reportDiagnostic, reportWatchDiagnostic, beforeCompile, afterCompile } = watchingHost;
Expand Down Expand Up @@ -292,7 +293,8 @@ namespace ts {
function synchronizeProgram() {
writeLog(`Synchronizing program`);

if (isProgramUptoDate(program, rootFileNames, compilerOptions, getSourceVersion, fileExists)) {
hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution();
if (isProgramUptoDate(program, rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution)) {
return;
}

Expand All @@ -306,7 +308,7 @@ namespace ts {

// Compile the program
program = createProgram(rootFileNames, compilerOptions, compilerHost, program);
builder.onProgramUpdateGraph(program);
builder.onProgramUpdateGraph(program, hasInvalidatedResolution);

// Update watches
missingFilesMap = updateMissingFilePathsWatch(program, missingFilesMap, watchMissingFilePath, closeMissingFilePathWatcher);
Expand Down Expand Up @@ -351,7 +353,8 @@ namespace ts {
realpath,
resolveTypeReferenceDirectives: (typeDirectiveNames, containingFile) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile),
resolveModuleNames: (moduleNames, containingFile) => resolutionCache.resolveModuleNames(moduleNames, containingFile, /*logChanges*/ false),
onReleaseOldSourceFile
onReleaseOldSourceFile,
hasInvalidatedResolution
};
}

Expand Down Expand Up @@ -569,13 +572,7 @@ namespace ts {
writeLog(`Failed lookup location : ${failedLookupLocation} changed: ${FileWatcherEventKind[eventKind]}, fileName: ${fileName} containingFile: ${containingFile}, name: ${name}`);
const path = toPath(failedLookupLocation);
updateCachedSystem(failedLookupLocation, path);

// TODO: We need more intensive approach wherein we are able to comunicate to the program structure reuser that the even though the source file
// refering to this failed location hasnt changed, it needs to re-evaluate the module resolutions for the invalidated resolutions.
// For now just clear existing program, that should still reuse the source files but atleast compute the resolutions again.

// resolutionCache.invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation);
program = undefined;
resolutionCache.invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation);
scheduleProgramUpdate();
}

Expand Down
4 changes: 4 additions & 0 deletions src/server/lsHost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ namespace ts.server {

readonly trace: (s: string) => void;
readonly realpath?: (path: string) => string;

/*@internal*/
hasInvalidatedResolution: HasInvalidatedResolution;

/**
* This is the host that is associated with the project. This is normally same as projectService's host
* except in Configured projects where it is CachedServerHost so that we can cache the results of the
Expand Down
11 changes: 4 additions & 7 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,8 @@ namespace ts.server {
if (this.projectKind === ProjectKind.Configured) {
(this.lsHost.host as CachedServerHost).addOrDeleteFileOrFolder(toNormalizedPath(failedLookupLocation));
}
this.updateTypes();
// TODO: We need more intensive approach wherein we are able to comunicate to the program structure reuser that the even though the source file
// refering to this failed location hasnt changed, it needs to re-evaluate the module resolutions for the invalidated resolutions.
// For now just clear existing program, that should still reuse the source files but atleast compute the resolutions again.
// this.resolutionCache.invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation);
// this.markAsDirty();
this.resolutionCache.invalidateResolutionOfChangedFailedLookupLocation(failedLookupLocation);
this.markAsDirty();
this.projectService.delayUpdateProjectGraphAndInferredProjectsRefresh(this);
});
}
Expand Down Expand Up @@ -605,6 +601,7 @@ namespace ts.server {
*/
updateGraph(): boolean {
this.resolutionCache.startRecordingFilesWithChangedResolutions();
this.lsHost.hasInvalidatedResolution = this.resolutionCache.createHasInvalidatedResolution();

let hasChanges = this.updateGraphWorker();

Expand Down Expand Up @@ -640,7 +637,7 @@ namespace ts.server {
// otherwise tell it to drop its internal state
if (this.builder) {
if (this.languageServiceEnabled && this.compileOnSaveEnabled) {
this.builder.onProgramUpdateGraph(this.program);
this.builder.onProgramUpdateGraph(this.program, this.lsHost.hasInvalidatedResolution);
}
else {
this.builder.clear();
Expand Down
8 changes: 6 additions & 2 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1115,8 +1115,11 @@ namespace ts {
// Get a fresh cache of the host information
let hostCache = new HostCache(host, getCanonicalFileName);
const rootFileNames = hostCache.getRootFileNames();

const hasInvalidatedResolution: HasInvalidatedResolution = host.hasInvalidatedResolution || noop;

// If the program is already up-to-date, we can reuse it
if (isProgramUptoDate(program, rootFileNames, hostCache.compilationSettings(), path => hostCache.getVersion(path), fileExists)) {
if (isProgramUptoDate(program, rootFileNames, hostCache.compilationSettings(), path => hostCache.getVersion(path), fileExists, hasInvalidatedResolution)) {
return;
}

Expand Down Expand Up @@ -1155,7 +1158,8 @@ namespace ts {
getDirectories: path => {
return host.getDirectories ? host.getDirectories(path) : [];
},
onReleaseOldSourceFile
onReleaseOldSourceFile,
hasInvalidatedResolution
};
if (host.trace) {
compilerHost.trace = message => host.trace(message);
Expand Down
1 change: 1 addition & 0 deletions src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ namespace ts {
*/
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
hasInvalidatedResolution?: HasInvalidatedResolution;
directoryExists?(directoryName: string): boolean;

/*
Expand Down
0