Skip to content

Commit

Permalink
Handle the difference is useSourceOfProjectReferenceRedirect and proj…
Browse files Browse the repository at this point in the history
…ect reference files in the program so editor can use correct program
  • Loading branch information
sheetalkamat committed Jun 2, 2021
1 parent cd709a3 commit 95eeb32
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 52 deletions.
16 changes: 16 additions & 0 deletions src/compiler/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,15 @@ namespace ts {
filesByName: ESMap<Path, SourceFileOfProgramFromBuildInfo | Path | typeof missingSourceOfProjectReferenceRedirect | typeof missingFile>;
fileIncludeReasons: MultiMap<Path, FileIncludeReason>;
sourceFileFromExternalLibraryPath: Set<Path> | undefined;
sourceFileFromProjectReferencePath: Set<Path> | undefined;
redirectTargetsMap: MultiMap<Path, string>;
sourceFileToPackageName: ESMap<Path, string>;
projectReferences: readonly ProjectReference[] | undefined;
resolvedProjectReferences: readonly (ResolvedProjectReferenceOfProgramFromBuildInfo | undefined)[] | undefined;
automaticTypeDirectiveNames: string[] | undefined;
resolvedTypeReferenceDirectives: ESMap<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
fileProcessingDiagnostics: FilePreprocessingDiagnostic[] | undefined;
useSourceOfProjectReferenceRedirect: boolean;
}

export const enum BuilderFileEmit {
Expand Down Expand Up @@ -340,24 +342,28 @@ namespace ts {
if (!state.program || !state.compilerOptions.persistResolutions || state.persistedProgramState) return;
const filesByName = mapEntries(state.program.getFilesByNameMap(), (key, value) => [key, value ? value.path : value as SourceFileOfProgramFromBuildInfo | Path | typeof missingSourceOfProjectReferenceRedirect | typeof missingFile]);
let sourceFileFromExternalLibraryPath: Set<Path> | undefined;
let sourceFileFromProjectReferencePath: Set<Path> | undefined;
const files = mapToReadonlyArray(state.program.getSourceFiles(), toSourceFileOfProgramFromBuildInfo);
state.persistedProgramState = {
files,
rootFileNames: state.program.getRootFileNames(),
filesByName,
fileIncludeReasons: state.program.getFileIncludeReasons(),
sourceFileFromExternalLibraryPath,
sourceFileFromProjectReferencePath,
redirectTargetsMap: state.program.redirectTargetsMap,
sourceFileToPackageName: state.program.sourceFileToPackageName,
projectReferences: state.program.getProjectReferences(),
resolvedProjectReferences: state.program.getResolvedProjectReferences()?.map(toResolvedProjectReferenceOfProgramFromBuildInfo),
resolvedTypeReferenceDirectives: state.program.getResolvedTypeReferenceDirectives(),
automaticTypeDirectiveNames: state.program.getAutomaticTypeDirectiveNames(),
fileProcessingDiagnostics: state.program.getFileProcessingDiagnostics(),
useSourceOfProjectReferenceRedirect: state.program.useSourceOfProjectReferenceRedirect,
};

function toSourceFileOfProgramFromBuildInfo(sourceFile: SourceFile): SourceFileOfProgramFromBuildInfo {
if (state.program!.isSourceFileFromExternalLibraryPath(sourceFile.path)) (sourceFileFromExternalLibraryPath ||= new Set()).add(sourceFile.path);
if (sourceFile.resolvedPath !== sourceFile.path && state.program!.isSourceFileFromExternalLibraryPath(sourceFile.path)) (sourceFileFromExternalLibraryPath ||= new Set()).add(sourceFile.path);
const file: SourceFileOfProgramFromBuildInfo = {
fileName: sourceFile.fileName,
originalFileName: sourceFile.originalFileName,
Expand Down Expand Up @@ -878,6 +884,7 @@ namespace ts {

includeReasons: readonly PersistedProgramFileIncludeReason[];
isSourceFileFromExternalLibraryPath?: true;
isSourceFileFromProjectReference?: true;
redirectTargets?: readonly ProgramBuildInfoAbsoluteFileId[];
packageName?: string;
}
Expand Down Expand Up @@ -924,6 +931,7 @@ namespace ts {
resolvedTypeReferenceDirectives: readonly PersistedProgramResolutionEntry[] | undefined;
fileProcessingDiagnostics: readonly PersistedProgramFilePreprocessingDiagnostic[] | undefined;
resolutions: readonly PersistedProgramResolution[] | undefined;
useSourceOfProjectReferenceRedirect: true | undefined;
}
export interface ProgramBuildInfo {
fileNames: readonly string[];
Expand Down Expand Up @@ -1036,6 +1044,7 @@ namespace ts {
automaticTypeDirectiveNames: program.getAutomaticTypeDirectiveNames()?.length ? program.getAutomaticTypeDirectiveNames() : undefined,
fileProcessingDiagnostics: mapToReadonlyArrayOrUndefined(program.getFileProcessingDiagnostics(), toPersistedProgramFilePreprocessingDiagnostic),
resolutions: mapToReadonlyArrayOrUndefined(resolutions, toPersistedProgramResolution),
useSourceOfProjectReferenceRedirect: program.useSourceOfProjectReferenceRedirect ? true : undefined
};
}
return {
Expand Down Expand Up @@ -1109,6 +1118,7 @@ namespace ts {
redirectTargets: mapToReadonlyArrayOrUndefined(program.redirectTargetsMap.get(sourceFile.path), toAbsoluteFileId),
includeReasons: program.getFileIncludeReasons().get(sourceFile.path)!.map(toPersistedProgramFileIncludeReason),
isSourceFileFromExternalLibraryPath: program.isSourceFileFromExternalLibraryPath(sourceFile.path) ? true : undefined,
isSourceFileFromProjectReference: sourceFile.path !== sourceFile.resolvedPath && program.isSourceFileFromProjectReference(sourceFile) ? true : undefined,
packageName: program.sourceFileToPackageName.get(sourceFile.path),
};
}
Expand Down Expand Up @@ -1726,6 +1736,7 @@ namespace ts {
const filesByName = new Map<Path, SourceFileOfProgramFromBuildInfo | Path | typeof missingSourceOfProjectReferenceRedirect | typeof missingFile>();
const fileIncludeReasons = createMultiMap<Path, FileIncludeReason>();
let sourceFileFromExternalLibraryPath: Set<Path> | undefined;
let sourceFileFromProjectReferencePath: Set<Path> | undefined;
const redirectTargetsMap = createMultiMap<Path, string>();
const sourceFileToPackageName = new Map<Path, string>();
program.peristedProgram.filesByName?.forEach(entry => {
Expand All @@ -1745,13 +1756,15 @@ namespace ts {
filesByName,
fileIncludeReasons,
sourceFileFromExternalLibraryPath,
sourceFileFromProjectReferencePath,
redirectTargetsMap,
sourceFileToPackageName,
projectReferences: program.peristedProgram.projectReferences?.map(toProjectReference),
resolvedProjectReferences: program.peristedProgram.resolvedProjectReferences?.map(toResolvedProjectReference),
automaticTypeDirectiveNames: program.peristedProgram.automaticTypeDirectiveNames,
resolvedTypeReferenceDirectives: toResolutionMap(program.peristedProgram.resolvedTypeReferenceDirectives) || new Map(),
fileProcessingDiagnostics: map(program.peristedProgram.fileProcessingDiagnostics, toFileProcessingDiagnostic),
useSourceOfProjectReferenceRedirect: !!program.peristedProgram.useSourceOfProjectReferenceRedirect,
};
return {
program: createProgramFromPersistedProgramState(persistedProgramState, compilerOptions),
Expand All @@ -1764,6 +1777,7 @@ namespace ts {

fileIncludeReasons.set(path, file.includeReasons.map(toFileIncludeReason));
if (file.isSourceFileFromExternalLibraryPath) (sourceFileFromExternalLibraryPath ||= new Set()).add(path);
if (file.isSourceFileFromProjectReference) (sourceFileFromProjectReferencePath ||= new Set()).add(path);
if (file.redirectTargets) redirectTargetsMap.set(path, file.redirectTargets.map(toFileAbsolutePath));
if (file.packageName) sourceFileToPackageName.set(path, file.packageName);

Expand Down Expand Up @@ -1874,9 +1888,11 @@ namespace ts {
getResolvedTypeReferenceDirectives: () => persistedProgramState.resolvedTypeReferenceDirectives,
getFilesByNameMap: () => persistedProgramState.filesByName,
isSourceFileFromExternalLibraryPath: path => !!persistedProgramState.sourceFileFromExternalLibraryPath?.has(path),
isSourceFileFromProjectReference: file => !!persistedProgramState.sourceFileFromProjectReferencePath?.has(file.path),
getFileProcessingDiagnostics: () => persistedProgramState.fileProcessingDiagnostics,
redirectTargetsMap: persistedProgramState.redirectTargetsMap,
sourceFileToPackageName: persistedProgramState.sourceFileToPackageName,
useSourceOfProjectReferenceRedirect: persistedProgramState.useSourceOfProjectReferenceRedirect
};
}

Expand Down
14 changes: 14 additions & 0 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,8 @@ namespace ts {
realpath: host.realpath?.bind(host),
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
getFileIncludeReasons: () => fileReasons,
isSourceFileFromProjectReference,
useSourceOfProjectReferenceRedirect,
structureIsReused,
};

Expand Down Expand Up @@ -1569,6 +1571,11 @@ namespace ts {
newSourceFile.resolvedPath = oldSourceFile.resolvedPath;
newSourceFile.fileName = oldSourceFile.fileName;

if (oldProgram.useSourceOfProjectReferenceRedirect !== useSourceOfProjectReferenceRedirect &&
(newSourceFile.path !== newSourceFile.resolvedPath || oldProgram.isSourceFileFromProjectReference(oldSourceFile as SourceFile & SourceFileOfProgramFromBuildInfo))) {
return StructureIsReused.Not;
}

const packageName = oldProgram.sourceFileToPackageName.get(oldSourceFile.path);
if (packageName !== undefined) {
// If there are 2 different source files for the same package name and at least one of them changes,
Expand Down Expand Up @@ -2849,6 +2856,13 @@ namespace ts {
return referencedProjectPath && getResolvedProjectReferenceByPath(referencedProjectPath);
}

function isSourceFileFromProjectReference(file: SourceFile) {
return file.resolvedPath !== file.path ||
useSourceOfProjectReferenceRedirect ?
!!getProjectReferenceRedirectProject(file.fileName) : // Is this source of project reference
!!getSourceOfProjectReferenceRedirect(file.fileName); // Is this output of project reference
}

function forEachResolvedProjectReference<T>(
cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined
): T | undefined {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3956,6 +3956,8 @@ namespace ts {
/** Is the file emitted file */
/* @internal */ isEmittedFile(file: string): boolean;
/* @internal */ getFileIncludeReasons(): MultiMap<Path, FileIncludeReason>;
/* @internal */ useSourceOfProjectReferenceRedirect: boolean;
/* @internal */ isSourceFileFromProjectReference(file: SourceFile): boolean;
/* @internal */ useCaseSensitiveFileNames(): boolean;

getProjectReferences(): readonly ProjectReference[] | undefined;
Expand Down Expand Up @@ -4045,7 +4047,9 @@ namespace ts {
getFilesByNameMap(): ESMap<Path, SourceFileOfProgramFromBuildInfo | Path | typeof missingSourceOfProjectReferenceRedirect | typeof missingFile>;
isSourceFileFromExternalLibraryPath(path: Path): boolean;
getFileProcessingDiagnostics(): FilePreprocessingDiagnostic[] | undefined;
isSourceFileFromProjectReference(file: SourceFileOfProgramFromBuildInfo): boolean;

useSourceOfProjectReferenceRedirect: boolean;
redirectTargetsMap: MultiMap<Path, string>;
sourceFileToPackageName: ESMap<Path, string>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,41 +62,56 @@ DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/core 1 u
Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/core 1 undefined Config: /user/username/projects/myproject/core/tsconfig.json WatchType: Wild card directory
FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined WatchType: Closed Script info
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/core/myClass.d.ts 500 undefined WatchType: Closed Script info
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/core/anotherClass.d.ts 500 undefined WatchType: Closed Script info
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/logic/index.d.ts 500 undefined WatchType: Closed Script info
Reusing resolution of module '../logic' from '/user/username/projects/myproject/tests/index.ts' of old program, it was successfully resolved to '/user/username/projects/myproject/logic/index.ts'.
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/logic/index.ts 500 undefined WatchType: Closed Script info
Reusing resolution of module '../core/myClass' from '/user/username/projects/myproject/logic/index.ts' of old program, it was successfully resolved to '/user/username/projects/myproject/core/myClass.ts'.
Reusing resolution of module '../core/anotherClass' from '/user/username/projects/myproject/logic/index.ts' of old program, it was successfully resolved to '/user/username/projects/myproject/core/anotherClass.ts'.
======== Resolving module '../core' from '/user/username/projects/myproject/logic/index.ts'. ========
Using compiler options of project reference redirect '/user/username/projects/myproject/logic/tsconfig.json'.
Module resolution kind is not specified, using 'NodeJs'.
Loading module as file / folder, candidate module location '/user/username/projects/myproject/core', target file type 'TypeScript'.
File '/user/username/projects/myproject/core.ts' does not exist.
File '/user/username/projects/myproject/core.tsx' does not exist.
File '/user/username/projects/myproject/core.d.ts' does not exist.
File '/user/username/projects/myproject/core/package.json' does not exist.
File '/user/username/projects/myproject/core/index.ts' exist - use it as a name resolution result.
======== Module name '../core' was successfully resolved to '/user/username/projects/myproject/core/index.ts'. ========
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/core/myClass.ts 500 undefined WatchType: Closed Script info
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/core/index.ts 500 undefined WatchType: Closed Script info
FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/core/anotherClass.ts 500 undefined WatchType: Closed Script info
DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/tests/node_modules/@types 1 undefined Project: /user/username/projects/myproject/tests/tsconfig.json WatchType: Type roots
Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/tests/node_modules/@types 1 undefined Project: /user/username/projects/myproject/tests/tsconfig.json WatchType: Type roots
DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/node_modules/@types 1 undefined Project: /user/username/projects/myproject/tests/tsconfig.json WatchType: Type roots
Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/node_modules/@types 1 undefined Project: /user/username/projects/myproject/tests/tsconfig.json WatchType: Type roots
Finishing updateGraphWorker: Project: /user/username/projects/myproject/tests/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Completely Elapsed:: *ms
Finishing updateGraphWorker: Project: /user/username/projects/myproject/tests/tsconfig.json Version: 1 structureChanged: true structureIsReused:: SafeModules Elapsed:: *ms
Project '/user/username/projects/myproject/tests/tsconfig.json' (Configured)
Files (5)
Files (6)
/a/lib/lib.d.ts
/user/username/projects/myproject/core/myClass.d.ts
/user/username/projects/myproject/core/anotherClass.d.ts
/user/username/projects/myproject/logic/index.d.ts
/user/username/projects/myproject/core/myClass.ts
/user/username/projects/myproject/core/index.ts
/user/username/projects/myproject/core/anotherClass.ts
/user/username/projects/myproject/logic/index.ts
/user/username/projects/myproject/tests/index.ts
../../../../../a/lib/lib.d.ts
Default library
../core/myClass.d.ts
Imported via "../core/myClass" from file '../logic/index.d.ts'
File is output of project reference source '../core/myClass.ts'
../core/anotherClass.d.ts
Imported via "../core/anotherClass" from file '../logic/index.d.ts'
File is output of project reference source '../core/anotherClass.ts'
../logic/index.d.ts
../core/myClass.ts
Imported via "../core/myClass" from file '../logic/index.ts'
../core/index.ts
Imported via "../core" from file '../logic/index.ts'
../core/anotherClass.ts
Imported via "../core/anotherClass" from file '../logic/index.ts'
../logic/index.ts
Imported via "../logic" from file 'index.ts'
File is output of project reference source '../logic/index.ts'
index.ts
Matched by include pattern '**/*' in 'tsconfig.json'

-----------------------------------------------
Search path: /user/username/projects/myproject/tests
For info: /user/username/projects/myproject/tests/tsconfig.json :: No config files found.
Project '/user/username/projects/myproject/tests/tsconfig.json' (Configured)
Files (5)
Files (6)

-----------------------------------------------
Open files:
Expand All @@ -117,22 +132,26 @@ interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }

{"fileName":"/user/username/projects/myproject/core/myClass.d.ts","version":"-7432826827-export declare class myClass {\n}\n"}
export declare class myClass {
}

{"fileName":"/user/username/projects/myproject/core/myClass.ts","version":"-11785903855-export class myClass { }"}
export class myClass { }

{"fileName":"/user/username/projects/myproject/core/anotherClass.d.ts","version":"-6928009824-export declare class anotherClass {\n}\n"}
export declare class anotherClass {
}
{"fileName":"/user/username/projects/myproject/core/index.ts","version":"4120767815-export function bar() { return 10; }"}
export function bar() { return 10; }

{"fileName":"/user/username/projects/myproject/core/anotherClass.ts","version":"-6664885476-export class anotherClass { }"}
export class anotherClass { }

{"fileName":"/user/username/projects/myproject/logic/index.d.ts","version":"-26318514585-import { myClass } from \"../core/myClass\";\nimport { anotherClass } from \"../core/anotherClass\";\nexport declare function returnMyClass(): myClass;\nexport declare function returnAnotherClass(): anotherClass;\n"}
{"fileName":"/user/username/projects/myproject/logic/index.ts","version":"-8233748805-import { myClass } from \"../core/myClass\";\nimport { bar } from \"../core\";\nimport { anotherClass } from \"../core/anotherClass\";\nexport function returnMyClass() {\n bar();\n return new myClass();\n}\nexport function returnAnotherClass() {\n return new anotherClass();\n}"}
import { myClass } from "../core/myClass";
import { bar } from "../core";
import { anotherClass } from "../core/anotherClass";
export declare function returnMyClass(): myClass;
export declare function returnAnotherClass(): anotherClass;

export function returnMyClass() {
bar();
return new myClass();
}
export function returnAnotherClass() {
return new anotherClass();
}

{"fileName":"/user/username/projects/myproject/tests/index.ts","version":"-2125404654-import { returnMyClass } from \"../logic\";\nreturnMyClass();"}
import { returnMyClass } from "../logic";
Expand Down
Loading

0 comments on commit 95eeb32

Please sign in to comment.