Handle resolution caching when referenced tsconfig changes

This commit is contained in:
Sheetal Nandi
2018-10-04 15:04:12 -07:00
parent d4e4b43239
commit 94df5167b0
11 changed files with 253 additions and 98 deletions
+2
View File
@@ -1294,6 +1294,8 @@ namespace ts {
const result = parseJsonText(configFileName, configFileText);
const cwd = host.getCurrentDirectory();
result.path = toPath(configFileName, cwd, createGetCanonicalFileName(host.useCaseSensitiveFileNames));
result.resolvedPath = result.path;
result.originalFileName = result.fileName;
return parseJsonSourceFileConfigFileContent(result, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd));
}
+107 -54
View File
@@ -487,7 +487,7 @@ namespace ts {
function sourceFileNotUptoDate(sourceFile: SourceFile) {
return !sourceFileVersionUptoDate(sourceFile) ||
hasInvalidatedResolution(sourceFile.resolvedPath);
hasInvalidatedResolution(sourceFile.path);
}
function sourceFileVersionUptoDate(sourceFile: SourceFile) {
@@ -752,10 +752,18 @@ namespace ts {
if (oldProgram && host.onReleaseOldSourceFile) {
const oldSourceFiles = oldProgram.getSourceFiles();
for (const oldSourceFile of oldSourceFiles) {
if (!getSourceFile(oldSourceFile.path) || shouldCreateNewSourceFile) {
host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions());
const newFile = getSourceFileByPath(oldSourceFile.resolvedPath);
if (shouldCreateNewSourceFile || !newFile ||
// old file wasnt redirect but new file is
(oldSourceFile.resolvedPath === oldSourceFile.path && newFile.resolvedPath !== oldSourceFile.path)) {
host.onReleaseOldSourceFile(oldSourceFile, oldProgram.getCompilerOptions(), !!getSourceFileByPath(oldSourceFile.path));
}
}
oldProgram.forEachResolvedProjectReference((resolvedProjectReference, resolvedProjectReferencePath) => {
if (resolvedProjectReference && !getResolvedProjectReferenceByPath(resolvedProjectReferencePath)) {
host.onReleaseOldSourceFile!(resolvedProjectReference.sourceFile, oldProgram!.getCompilerOptions(), /*hasSourceFileByPath*/ false);
}
});
}
// unconditionally set oldProgram to undefined to prevent it from being captured in closure
@@ -798,7 +806,10 @@ namespace ts {
getResolvedModuleWithFailedLookupLocationsFromCache,
getProjectReferences,
getResolvedProjectReferences,
getProjectReferenceRedirect
getProjectReferenceRedirect,
getResolvedProjectReferenceToRedirect,
getResolvedProjectReferenceByPath,
forEachResolvedProjectReference
};
verifyCompilerOptions();
@@ -881,7 +892,7 @@ namespace ts {
if (structuralIsReused === StructureIsReused.Not && !file.ambientModuleNames.length) {
// If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules,
// the best we can do is fallback to the default logic.
return resolveModuleNamesWorker(moduleNames, containingFile, /*reusedNames*/ undefined, getProjectReferenceRedirectProject(file.originalFileName));
return resolveModuleNamesWorker(moduleNames, containingFile, /*reusedNames*/ undefined, getResolvedProjectReferenceToRedirect(file.originalFileName));
}
const oldSourceFile = oldProgramState.program && oldProgramState.program.getSourceFile(containingFile);
@@ -961,7 +972,7 @@ namespace ts {
}
const resolutions = unknownModuleNames && unknownModuleNames.length
? resolveModuleNamesWorker(unknownModuleNames, containingFile, reusedNames, getProjectReferenceRedirectProject(file.originalFileName))
? resolveModuleNamesWorker(unknownModuleNames, containingFile, reusedNames, getResolvedProjectReferenceToRedirect(file.originalFileName))
: emptyArray;
// Combine results of resolutions and predicted results
@@ -1021,46 +1032,28 @@ namespace ts {
}
}
function canReuseProjectReferences(
newProjectReferences: ReadonlyArray<ProjectReference> | undefined,
oldProjectReferences: ReadonlyArray<ProjectReference> | undefined,
oldResolvedReferences: ReadonlyArray<ResolvedProjectReference | undefined> | undefined): boolean {
// If array of references is changed, we cant resue old program
if (!arrayIsEqualTo(oldProjectReferences!, newProjectReferences, projectReferenceIsEqualTo)) {
return false;
}
// Check the json files for the project references
if (newProjectReferences) {
// Resolved project referenced should be array if projectReferences provided are array
Debug.assert(!!oldResolvedReferences);
for (let i = 0; i < newProjectReferences.length; i++) {
const oldRef = oldResolvedReferences![i];
const newRef = parseProjectReferenceConfigFile(newProjectReferences[i]);
if (oldRef) {
if (!newRef || newRef.sourceFile !== oldRef.sourceFile) {
// Resolved project reference has gone missing or changed
return false;
}
// If the transitive references can be reused then only this reference can be reused
if (!canReuseProjectReferences(newRef.commandLine.projectReferences, oldRef.commandLine.projectReferences, oldRef.references)) {
return false;
}
function canReuseProjectReferences(): boolean {
return !forEachProjectReference(
oldProgram!.getProjectReferences(),
oldProgram!.getResolvedProjectReferences(),
(oldResolvedRef, index, parent) => {
const newRef = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
const newResolvedRef = parseProjectReferenceConfigFile(newRef);
if (oldResolvedRef) {
// Resolved project reference has gone missing or changed
return !newResolvedRef || newResolvedRef.sourceFile !== oldResolvedRef.sourceFile;
}
else {
// A previously-unresolved reference may be resolved now
if (newRef !== undefined) {
return false;
}
return newResolvedRef !== undefined;
}
},
(oldProjectReferences, parent) => {
// If array of references is changed, we cant resue old program
const newReferences = parent ? getResolvedProjectReferenceByPath(parent.sourceFile.path)!.commandLine.projectReferences : projectReferences;
return !arrayIsEqualTo(oldProjectReferences, newReferences, projectReferenceIsEqualTo);
}
}
else {
// Resolved project referenced should be undefined if projectReferences is undefined
Debug.assert(!oldResolvedReferences);
}
return true;
);
}
function tryReuseStructureFromOldProgram(): StructureIsReused {
@@ -1088,7 +1081,7 @@ namespace ts {
}
// Check if any referenced project tsconfig files are different
if (!canReuseProjectReferences(projectReferences, oldProgram.getProjectReferences(), oldProgram.getResolvedProjectReferences())) {
if (!canReuseProjectReferences()) {
return oldProgram.structureIsReused = StructureIsReused.Not;
}
resolvedProjectReferences = oldProgram.getResolvedProjectReferences();
@@ -1240,7 +1233,7 @@ namespace ts {
if (resolveTypeReferenceDirectiveNamesWorker) {
// We lower-case all type references because npm automatically lowercases all packages. See GH#9824.
const typesReferenceDirectives = map(newSourceFile.typeReferenceDirectives, ref => ref.fileName.toLocaleLowerCase());
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typesReferenceDirectives, newSourceFilePath, getProjectReferenceRedirectProject(newSourceFile.originalFileName));
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typesReferenceDirectives, newSourceFilePath, getResolvedProjectReferenceToRedirect(newSourceFile.originalFileName));
// ensure that types resolutions are still correct
const resolutionsChanged = hasChangesInResolutions(typesReferenceDirectives, resolutions, oldSourceFile.resolvedTypeReferenceDirectiveNames, typeDirectiveIsEqualTo);
if (resolutionsChanged) {
@@ -2215,7 +2208,7 @@ namespace ts {
// If this file is produced by a referenced project, we need to rewrite it to
// look in the output folder of the referenced project rather than the input
const referencedProject = getProjectReferenceRedirectProject(fileName);
const referencedProject = getResolvedProjectReferenceToRedirect(fileName);
if (!referencedProject) {
return undefined;
}
@@ -2229,16 +2222,11 @@ namespace ts {
/**
* Get the referenced project if the file is input file from that reference project
*/
function getProjectReferenceRedirectProject(fileName: string) {
if (!resolvedProjectReferences || !resolvedProjectReferences.length) {
return undefined;
}
// If this file is input file of the referenced projec
return forEachEntry(projectReferenceRedirects!, referencedProject => {
function getResolvedProjectReferenceToRedirect(fileName: string) {
return forEachResolvedProjectReference((referencedProject, referenceProjectPath) => {
// not input file from the referenced project, ignore
if (!referencedProject ||
options.configFilePath === referencedProject.commandLine.options.configFilePath ||
toPath(options.configFilePath!) === referenceProjectPath ||
!contains(referencedProject.commandLine.fileNames, fileName, isSameFile)) {
return undefined;
}
@@ -2247,6 +2235,67 @@ namespace ts {
});
}
function forEachResolvedProjectReference<T>(
cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined
): T | undefined {
return forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, index, parent) => {
const ref = (parent ? parent.commandLine.projectReferences : projectReferences)![index];
const resolvedRefPath = toPath(resolveProjectReferencePath(ref));
return cb(resolvedRef, resolvedRefPath);
});
}
function forEachProjectReference<T>(
projectReferences: ReadonlyArray<ProjectReference> | undefined,
resolvedProjectReferences: ReadonlyArray<ResolvedProjectReference | undefined> | undefined,
cbResolvedRef: (resolvedRef: ResolvedProjectReference | undefined, index: number, parent: ResolvedProjectReference | undefined) => T | undefined,
cbRef?: (projectReferences: ReadonlyArray<ProjectReference> | undefined, parent: ResolvedProjectReference | undefined) => T | undefined
): T | undefined {
let seenResolvedRefs: ResolvedProjectReference[] | undefined;
return worker(projectReferences, resolvedProjectReferences, /*parent*/ undefined, cbResolvedRef, cbRef);
function worker(
projectReferences: ReadonlyArray<ProjectReference> | undefined,
resolvedProjectReferences: ReadonlyArray<ResolvedProjectReference | undefined> | undefined,
parent: ResolvedProjectReference | undefined,
cbResolvedRef: (resolvedRef: ResolvedProjectReference | undefined, index: number, parent: ResolvedProjectReference | undefined) => T | undefined,
cbRef?: (projectReferences: ReadonlyArray<ProjectReference> | undefined, parent: ResolvedProjectReference | undefined) => T | undefined,
): T | undefined {
// Visit project references first
if (cbRef) {
const result = cbRef(projectReferences, parent);
if (result) { return result; }
}
return forEach(resolvedProjectReferences, (resolvedRef, index) => {
if (contains(seenResolvedRefs, resolvedRef)) {
// ignore recursives
return undefined;
}
const result = cbResolvedRef(resolvedRef, index, parent);
if (result) {
return result;
}
if (!resolvedRef) return undefined;
(seenResolvedRefs || (seenResolvedRefs = [])).push(resolvedRef);
return worker(resolvedRef.commandLine.projectReferences, resolvedRef.references, resolvedRef, cbResolvedRef, cbRef);
});
}
}
function getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined {
if (!projectReferenceRedirects) {
return undefined;
}
return projectReferenceRedirects.get(projectReferencePath) || undefined;
}
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
forEach(file.referencedFiles, ref => {
const referencedFileName = resolveTripleslashReference(ref.fileName, file.originalFileName);
@@ -2261,7 +2310,7 @@ namespace ts {
return;
}
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file.originalFileName, getProjectReferenceRedirectProject(file.originalFileName));
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file.originalFileName, getResolvedProjectReferenceToRedirect(file.originalFileName));
for (let i = 0; i < typeDirectives.length; i++) {
const ref = file.typeReferenceDirectives[i];
@@ -2450,11 +2499,14 @@ namespace ts {
// An absolute path pointing to the containing directory of the config file
const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
addFileToFilesByName(sourceFile, sourceFilePath, /*redirectedPath*/ undefined);
if (sourceFile === undefined) {
projectReferenceRedirects.set(sourceFilePath, false);
return undefined;
}
sourceFile.path = sourceFilePath;
sourceFile.resolvedPath = sourceFilePath;
sourceFile.originalFileName = refPath;
const commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath);
const resolvedRef: ResolvedProjectReference = { commandLine, sourceFile };
projectReferenceRedirects.set(sourceFilePath, resolvedRef);
@@ -2506,12 +2558,13 @@ namespace ts {
}
}
//TODO:: Errors on transitive references
if (projectReferences) {
for (let i = 0; i < projectReferences.length; i++) {
const ref = projectReferences[i];
const resolvedRefOpts = resolvedProjectReferences![i] && resolvedProjectReferences![i]!.commandLine.options;
if (resolvedRefOpts === undefined) {
createDiagnosticForReference(i, Diagnostics.File_0_does_not_exist, ref.path);
createDiagnosticForReference(i, Diagnostics.File_0_not_found, ref.path);
continue;
}
if (!resolvedRefOpts.composite) {
+25 -1
View File
@@ -11,6 +11,7 @@ namespace ts {
invalidateResolutionOfFile(filePath: Path): void;
removeResolutionsOfFile(filePath: Path): void;
removeResolutionsFromProjectReferenceRedirects(filePath: Path): void;
setFilesWithInvalidatedNonRelativeUnresolvedImports(filesWithUnresolvedImports: Map<ReadonlyArray<string>>): void;
createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution;
@@ -128,6 +129,7 @@ namespace ts {
resolveModuleNames,
getResolvedModuleWithFailedLookupLocationsFromCache,
resolveTypeReferenceDirectives,
removeResolutionsFromProjectReferenceRedirects,
removeResolutionsOfFile,
invalidateResolutionOfFile,
setFilesWithInvalidatedNonRelativeUnresolvedImports,
@@ -262,12 +264,20 @@ namespace ts {
const resolvedModules: R[] = [];
const compilerOptions = resolutionHost.getCompilationSettings();
const hasInvalidatedNonRelativeUnresolvedImport = logChanges && isFileWithInvalidatedNonRelativeUnresolvedImports(path);
// All the resolutions in this file are invalidated if this file wasnt resolved using same redirect
const program = resolutionHost.getCurrentProgram();
const oldRedirect = program && program.getResolvedProjectReferenceToRedirect(containingFile);
const unmatchedRedirects = oldRedirect ?
!redirectedReference || redirectedReference.sourceFile.path !== oldRedirect.sourceFile.path :
!!redirectedReference;
const seenNamesInFile = createMap<true>();
for (const name of names) {
let resolution = resolutionsInFile.get(name);
// Resolution is valid if it is present and not invalidated
if (!seenNamesInFile.has(name) &&
allFilesHaveInvalidatedResolution || !resolution || resolution.isInvalidated ||
allFilesHaveInvalidatedResolution || unmatchedRedirects || !resolution || resolution.isInvalidated ||
// If the name is unresolved import that was invalidated, recalculate
(hasInvalidatedNonRelativeUnresolvedImport && !isExternalModuleNameRelative(name) && !getResolutionWithResolvedFileName(resolution))) {
const existingResolution = resolution;
@@ -596,6 +606,20 @@ namespace ts {
}
}
function removeResolutionsFromProjectReferenceRedirects(filePath: Path) {
if (!fileExtensionIs(filePath, Extension.Json)) { return; }
const program = resolutionHost.getCurrentProgram();
if (!program) { return; }
// If this file is input file for the referenced project, get it
const resolvedProjectReference = program.getResolvedProjectReferenceByPath(filePath);
if (!resolvedProjectReference) { return; }
// filePath is for the projectReference and the containing file is from this project reference, invalidate the resolution
resolvedProjectReference.commandLine.fileNames.forEach(f => removeResolutionsOfFile(resolutionHost.toPath(f)));
}
function removeResolutionsOfFile(filePath: Path) {
removeResolutionsOfFileFromCache(resolvedModuleNames, filePath);
removeResolutionsOfFileFromCache(resolvedTypeReferenceDirectives, filePath);
+4 -1
View File
@@ -2831,6 +2831,9 @@ namespace ts {
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
getResolvedProjectReferences(): ReadonlyArray<ResolvedProjectReference | undefined> | undefined;
/*@internal*/ getProjectReferenceRedirect(fileName: string): string | undefined;
/*@internal*/ getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined;
/*@internal*/ forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined): T | undefined;
/*@internal*/ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined;
}
/* @internal */
@@ -4882,7 +4885,7 @@ namespace ts {
*/
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string, redirectedReference?: ResolvedProjectReference): ResolvedTypeReferenceDirective[];
getEnvironmentVariable?(name: string): string | undefined;
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions): void;
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions, hasSourceFileByPath: boolean): void;
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
createHash?(data: string): string;
+7 -4
View File
@@ -764,8 +764,8 @@ namespace ts {
return !hostSourceFile || isFileMissingOnHost(hostSourceFile) ? undefined : hostSourceFile.version.toString();
}
function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions) {
const hostSourceFileInfo = sourceFilesCache.get(oldSourceFile.path);
function onReleaseOldSourceFile(oldSourceFile: SourceFile, _oldOptions: CompilerOptions, hasSourceFileByPath: boolean) {
const hostSourceFileInfo = sourceFilesCache.get(oldSourceFile.resolvedPath);
// If this is the source file thats in the cache and new program doesnt need it,
// remove the cached entry.
// Note we arent deleting entry if file became missing in new program or
@@ -779,8 +779,10 @@ namespace ts {
if ((hostSourceFileInfo as FilePresentOnHost).fileWatcher) {
(hostSourceFileInfo as FilePresentOnHost).fileWatcher.close();
}
sourceFilesCache.delete(oldSourceFile.path);
resolutionCache.removeResolutionsOfFile(oldSourceFile.path);
sourceFilesCache.delete(oldSourceFile.resolvedPath);
if (oldSourceFile.resolvedPath === oldSourceFile.path || !hasSourceFileByPath) {
resolutionCache.removeResolutionsOfFile(oldSourceFile.path);
}
}
}
}
@@ -875,6 +877,7 @@ namespace ts {
if (eventKind === FileWatcherEventKind.Deleted && sourceFilesCache.get(path)) {
resolutionCache.invalidateResolutionOfFile(path);
}
resolutionCache.removeResolutionsFromProjectReferenceRedirects(path);
nextSourceFileVersion(path);
// Update the program
+20 -18
View File
@@ -871,15 +871,20 @@ namespace ts.server {
if (!info) {
this.logger.msg(`Error: got watch notification for unknown file: ${fileName}`);
}
else if (eventKind === FileWatcherEventKind.Deleted) {
// File was deleted
this.handleDeletedFile(info);
}
else if (!info.isScriptOpen()) {
// file has been changed which might affect the set of referenced files in projects that include
// this file and set of inferred projects
info.delayReloadNonMixedContentFile();
this.delayUpdateProjectGraphs(info.containingProjects);
else {
if (info.containingProjects) {
info.containingProjects.forEach(project => project.resolutionCache.removeResolutionsFromProjectReferenceRedirects(info.path));
}
if (eventKind === FileWatcherEventKind.Deleted) {
// File was deleted
this.handleDeletedFile(info);
}
else if (!info.isScriptOpen()) {
// file has been changed which might affect the set of referenced files in projects that include
// this file and set of inferred projects
info.delayReloadNonMixedContentFile();
this.delayUpdateProjectGraphs(info.containingProjects);
}
}
}
@@ -2434,17 +2439,14 @@ namespace ts.server {
}
else {
// If the configured project for project reference has more than zero references, keep it alive
const resolvedProjectReferences = project.getResolvedProjectReferences();
if (resolvedProjectReferences) {
for (const ref of resolvedProjectReferences) {
if (ref) {
const refProject = this.configuredProjects.get(ref.sourceFile.path);
if (refProject && refProject.hasOpenRef()) {
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
}
project.forEachResolvedProjectReference(ref => {
if (ref) {
const refProject = this.configuredProjects.get(ref.sourceFile.path);
if (refProject && refProject.hasOpenRef()) {
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
}
}
}
});
}
});
+21 -15
View File
@@ -583,14 +583,11 @@ namespace ts.server {
for (const f of this.program.getSourceFiles()) {
this.detachScriptInfoIfNotRoot(f.fileName);
}
const projectReferences = this.program.getResolvedProjectReferences();
if (projectReferences) {
for (const ref of projectReferences) {
if (ref) {
this.detachScriptInfoFromProject(ref.sourceFile.fileName);
}
this.program.forEachResolvedProjectReference(ref => {
if (ref) {
this.detachScriptInfoFromProject(ref.sourceFile.fileName);
}
}
});
}
// Release external files
forEach(this.externalFiles, externalFile => this.detachScriptInfoIfNotRoot(externalFile));
@@ -925,12 +922,19 @@ namespace ts.server {
if (hasNewProgram) {
if (oldProgram) {
for (const f of oldProgram.getSourceFiles()) {
if (this.program.getSourceFileByPath(f.path)) {
continue;
const newFile = this.program.getSourceFileByPath(f.resolvedPath);
if (!newFile || (f.resolvedPath === f.path && newFile.resolvedPath !== f.path)) {
// new program does not contain this file - detach it from the project
// - remove resolutions only if this is undirected file or doesnt have source file with the path in new program
this.detachScriptInfoFromProject(f.fileName, f.path !== f.resolvedPath && !!this.program.getSourceFileByPath(f.path));
}
// new program does not contain this file - detach it from the project
this.detachScriptInfoFromProject(f.fileName);
}
oldProgram.forEachResolvedProjectReference((resolvedProjectReference, resolvedProjectReferencePath) => {
if (resolvedProjectReference && !this.program.getResolvedProjectReferenceByPath(resolvedProjectReferencePath)) {
this.detachScriptInfoFromProject(resolvedProjectReference.sourceFile.fileName);
}
});
}
// Update the missing file paths watcher
@@ -964,11 +968,13 @@ namespace ts.server {
return hasNewProgram;
}
private detachScriptInfoFromProject(uncheckedFileName: string) {
private detachScriptInfoFromProject(uncheckedFileName: string, noRemoveResolution?: boolean) {
const scriptInfoToDetach = this.projectService.getScriptInfo(uncheckedFileName);
if (scriptInfoToDetach) {
scriptInfoToDetach.detachFromProject(this);
this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path);
if (!noRemoveResolution) {
this.resolutionCache.removeResolutionsOfFile(scriptInfoToDetach.path);
}
}
}
@@ -1400,9 +1406,9 @@ namespace ts.server {
}
/*@internal*/
getResolvedProjectReferences() {
forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined): T | undefined {
const program = this.getCurrentProgram();
return program && program.getResolvedProjectReferences();
return program && program.forEachResolvedProjectReference(cb);
}
enablePlugins() {
+1 -1
View File
@@ -1276,7 +1276,7 @@ namespace ts {
// not part of the new program.
function onReleaseOldSourceFile(oldSourceFile: SourceFile, oldOptions: CompilerOptions) {
const oldSettingsKey = documentRegistry.getKeyForCompilationSettings(oldOptions);
documentRegistry.releaseDocumentWithKey(oldSourceFile.path, oldSettingsKey);
documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath, oldSettingsKey);
}
function getOrCreateSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined {
@@ -184,7 +184,7 @@ namespace ts {
};
testProjectReferences(spec, "/primary/tsconfig.json", program => {
const errs = program.getOptionsDiagnostics();
assertHasError("Reports an error about a missing file", errs, Diagnostics.File_0_does_not_exist);
assertHasError("Reports an error about a missing file", errs, Diagnostics.File_0_not_found);
});
});
+64 -2
View File
@@ -543,8 +543,8 @@ export function gfoo() {
}
function verifyProgram(host: WatchedSystem, watch: () => BuilderProgram) {
verifyWatchesOfProject(host, expectedWatchedFiles, expectedWatchedDirectoriesRecursive);
checkProgramActualFiles(watch().getProgram(), expectedProgramFiles);
verifyWatchesOfProject(host, expectedWatchedFiles, expectedWatchedDirectoriesRecursive);
verifyDependencies(watch, aDts, [aDts]);
verifyDependencies(watch, bDts, [bDts, aDts]);
verifyDependencies(watch, refs.path, [refs.path]);
@@ -588,12 +588,74 @@ export function gfoo() {
checkOutputErrorsIncremental(host, emptyArray);
const nrefReplacer = (f: string) => f.replace("refs", "nrefs");
verifyWatchesOfProject(host, expectedWatchedFiles.map(nrefReplacer), expectedWatchedDirectoriesRecursive.map(nrefReplacer));
checkProgramActualFiles(watch().getProgram(), expectedProgramFiles.map(nrefReplacer));
verifyWatchesOfProject(host, expectedWatchedFiles.map(nrefReplacer), expectedWatchedDirectoriesRecursive.map(nrefReplacer));
verifyDependencies(watch, aDts, [aDts]);
verifyDependencies(watch, bDts, [bDts, aDts]);
verifyDependencies(watch, nrefs.path, [nrefs.path]);
verifyDependencies(watch, cTs.path, [cTs.path, nrefs.path, bDts]);
// revert the update
host.writeFile(cTsconfig.path, cTsconfig.content);
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, emptyArray);
verifyProgram(host, watch);
});
it("edit in referenced config file", () => {
const { host, watch } = createSolutionAndWatchMode();
const nrefs: File = {
path: getFilePathInProject(project, "nrefs/a.d.ts"),
content: host.readFile(aDts)!
};
const bTsConfigJson = JSON.parse(bTsconfig.content);
host.ensureFileOrFolder(nrefs);
bTsConfigJson.compilerOptions.paths = { "@ref/*": ["./nrefs/*"] };
host.writeFile(bTsconfig.path, JSON.stringify(bTsConfigJson));
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, emptyArray);
const expectedProgramFiles = [cTs.path, bDts, nrefs.path, refs.path, libFile.path];
checkProgramActualFiles(watch().getProgram(), expectedProgramFiles);
verifyWatchesOfProject(host, expectedProgramFiles.concat(cTsconfig.path, bTsconfig.path, aTsconfig.path).map(s => s.toLowerCase()), expectedWatchedDirectoriesRecursive.concat(getFilePathInProject(project, "nrefs").toLowerCase()));
verifyDependencies(watch, nrefs.path, [nrefs.path]);
verifyDependencies(watch, bDts, [bDts, nrefs.path]);
verifyDependencies(watch, refs.path, [refs.path]);
verifyDependencies(watch, cTs.path, [cTs.path, refs.path, bDts]);
// revert the update
host.writeFile(bTsconfig.path, bTsconfig.content);
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, emptyArray);
verifyProgram(host, watch);
});
it("deleting referenced config file", () => {
const { host, watch } = createSolutionAndWatchMode();
// Resolutions should change now
// Should map to b.ts instead with options from our own config
host.deleteFile(bTsconfig.path);
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, [
"tsconfig.c.json(9,21): error TS6053: File '/user/username/projects/transitiveReferences/tsconfig.b.json' not found.\n"
]);
const expectedProgramFiles = [cTs.path, bTs.path, refs.path, libFile.path];
checkProgramActualFiles(watch().getProgram(), expectedProgramFiles);
verifyWatchesOfProject(host, expectedProgramFiles.concat(cTsconfig.path, bTsconfig.path).map(s => s.toLowerCase()), expectedWatchedDirectoriesRecursive);
verifyDependencies(watch, bTs.path, [bTs.path, refs.path]);
verifyDependencies(watch, refs.path, [refs.path]);
verifyDependencies(watch, cTs.path, [cTs.path, refs.path, bTs.path]);
// revert the update
host.writeFile(bTsconfig.path, bTsconfig.content);
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, emptyArray);
verifyProgram(host, watch);
});
});
});
@@ -5070,7 +5070,7 @@ namespace ts.projectSystem {
function getFileNotFoundDiagnostic(configFile: File, relativeFileName: string): ConfigFileDiagnostic {
const findString = `{"path":"./${relativeFileName}"}`;
const d = Diagnostics.File_0_does_not_exist;
const d = Diagnostics.File_0_not_found;
const start = configFile.content.indexOf(findString);
return {
fileName: configFile.path,