Skip to content

Commit 992c211

Browse files
authored
Merge pull request microsoft#32028 from microsoft/referencesPrototypeSourceFile
For editing experience, use source instead of .d.ts files from project references
2 parents 2e985e7 + fd3ba67 commit 992c211

27 files changed

+2202
-581
lines changed

src/compiler/builder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ namespace ts {
425425
const options = program.getCompilerOptions();
426426
forEach(program.getSourceFiles(), f =>
427427
program.isSourceFileDefaultLibrary(f) &&
428-
!skipTypeChecking(f, options) &&
428+
!skipTypeChecking(f, options, program) &&
429429
removeSemanticDiagnosticsOf(state, f.path)
430430
);
431431
}

src/compiler/checker.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ namespace ts {
572572
return node && getTypeArgumentConstraint(node);
573573
},
574574
getSuggestionDiagnostics: (file, ct) => {
575-
if (skipTypeChecking(file, compilerOptions)) {
575+
if (skipTypeChecking(file, compilerOptions, host)) {
576576
return emptyArray;
577577
}
578578

@@ -31048,7 +31048,7 @@ namespace ts {
3104831048
function checkSourceFileWorker(node: SourceFile) {
3104931049
const links = getNodeLinks(node);
3105031050
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
31051-
if (skipTypeChecking(node, compilerOptions)) {
31051+
if (skipTypeChecking(node, compilerOptions, host)) {
3105231052
return;
3105331053
}
3105431054

src/compiler/commandLineParser.ts

+6
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,12 @@ namespace ts {
772772
category: Diagnostics.Advanced_Options,
773773
description: Diagnostics.Disable_size_limitations_on_JavaScript_projects
774774
},
775+
{
776+
name: "disableSourceOfProjectReferenceRedirect",
777+
type: "boolean",
778+
category: Diagnostics.Advanced_Options,
779+
description: Diagnostics.Disable_use_of_source_files_instead_of_declaration_files_from_referenced_projects
780+
},
775781
{
776782
name: "noImplicitUseStrict",
777783
type: "boolean",

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -4036,6 +4036,10 @@
40364036
"category": "Message",
40374037
"code": 6220
40384038
},
4039+
"Disable use of source files instead of declaration files from referenced projects.": {
4040+
"category": "Message",
4041+
"code": 6221
4042+
},
40394043

40404044
"Projects to reference": {
40414045
"category": "Message",

src/compiler/program.ts

+87-11
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,8 @@ namespace ts {
817817
let resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined;
818818
let projectReferenceRedirects: Map<ResolvedProjectReference | false> | undefined;
819819
let mapFromFileToProjectReferenceRedirects: Map<Path> | undefined;
820+
let mapFromToProjectReferenceRedirectSource: Map<SourceOfProjectReferenceRedirect> | undefined;
821+
const useSourceOfProjectReferenceRedirect = !!host.useSourceOfProjectReferenceRedirect && host.useSourceOfProjectReferenceRedirect();
820822

821823
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
822824
// We set `structuralIsReused` to `undefined` because `tryReuseStructureFromOldProgram` calls `tryReuseStructureFromOldProgram` which checks
@@ -831,17 +833,32 @@ namespace ts {
831833
if (!resolvedProjectReferences) {
832834
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
833835
}
836+
if (host.setResolvedProjectReferenceCallbacks) {
837+
host.setResolvedProjectReferenceCallbacks({
838+
getSourceOfProjectReferenceRedirect,
839+
forEachResolvedProjectReference
840+
});
841+
}
834842
if (rootNames.length) {
835843
for (const parsedRef of resolvedProjectReferences) {
836844
if (!parsedRef) continue;
837845
const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out;
838-
if (out) {
839-
processSourceFile(changeExtension(out, ".d.ts"), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
846+
if (useSourceOfProjectReferenceRedirect) {
847+
if (out || getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
848+
for (const fileName of parsedRef.commandLine.fileNames) {
849+
processSourceFile(fileName, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
850+
}
851+
}
840852
}
841-
else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
842-
for (const fileName of parsedRef.commandLine.fileNames) {
843-
if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) {
844-
processSourceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames()), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
853+
else {
854+
if (out) {
855+
processSourceFile(changeExtension(out, ".d.ts"), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
856+
}
857+
else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
858+
for (const fileName of parsedRef.commandLine.fileNames) {
859+
if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) {
860+
processSourceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames()), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
861+
}
845862
}
846863
}
847864
}
@@ -955,6 +972,7 @@ namespace ts {
955972
getResolvedProjectReferenceToRedirect,
956973
getResolvedProjectReferenceByPath,
957974
forEachResolvedProjectReference,
975+
isSourceOfProjectReferenceRedirect,
958976
emitBuildInfo
959977
};
960978

@@ -987,9 +1005,15 @@ namespace ts {
9871005
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
9881006
}
9891007

1008+
function isValidSourceFileForEmit(file: SourceFile) {
1009+
// source file is allowed to be emitted and its not source of project reference redirect
1010+
return sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect) &&
1011+
!isSourceOfProjectReferenceRedirect(file.fileName);
1012+
}
1013+
9901014
function getCommonSourceDirectory() {
9911015
if (commonSourceDirectory === undefined) {
992-
const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect));
1016+
const emittedFiles = filter(files, file => isValidSourceFileForEmit(file));
9931017
if (options.rootDir && checkSourceFilesBelongToPath(emittedFiles, options.rootDir)) {
9941018
// If a rootDir is specified use it as the commonSourceDirectory
9951019
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, currentDirectory);
@@ -1220,6 +1244,12 @@ namespace ts {
12201244
}
12211245
if (projectReferences) {
12221246
resolvedProjectReferences = projectReferences.map(parseProjectReferenceConfigFile);
1247+
if (host.setResolvedProjectReferenceCallbacks) {
1248+
host.setResolvedProjectReferenceCallbacks({
1249+
getSourceOfProjectReferenceRedirect,
1250+
forEachResolvedProjectReference
1251+
});
1252+
}
12231253
}
12241254

12251255
// check if program source files has changed in the way that can affect structure of the program
@@ -1403,6 +1433,13 @@ namespace ts {
14031433
for (const newSourceFile of newSourceFiles) {
14041434
const filePath = newSourceFile.path;
14051435
addFileToFilesByName(newSourceFile, filePath, newSourceFile.resolvedPath);
1436+
if (useSourceOfProjectReferenceRedirect) {
1437+
const redirectProject = getProjectReferenceRedirectProject(newSourceFile.fileName);
1438+
if (redirectProject && !(redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out)) {
1439+
const redirect = getProjectReferenceOutputName(redirectProject, newSourceFile.fileName);
1440+
addFileToFilesByName(newSourceFile, toPath(redirect), /*redirectedPath*/ undefined);
1441+
}
1442+
}
14061443
// Set the file as found during node modules search if it was found that way in old progra,
14071444
if (oldProgram.isSourceFileFromExternalLibrary(oldProgram.getSourceFileByPath(newSourceFile.resolvedPath)!)) {
14081445
sourceFilesFoundSearchingNodeModules.set(filePath, true);
@@ -1682,7 +1719,7 @@ namespace ts {
16821719

16831720
function getSemanticDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] | undefined {
16841721
return runWithCancellationToken(() => {
1685-
if (skipTypeChecking(sourceFile, options)) {
1722+
if (skipTypeChecking(sourceFile, options, program)) {
16861723
return emptyArray;
16871724
}
16881725

@@ -2234,6 +2271,16 @@ namespace ts {
22342271

22352272
// Get source file from normalized fileName
22362273
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: RefFile | undefined, packageId: PackageId | undefined): SourceFile | undefined {
2274+
if (useSourceOfProjectReferenceRedirect) {
2275+
const source = getSourceOfProjectReferenceRedirect(fileName);
2276+
if (source) {
2277+
const file = isString(source) ?
2278+
findSourceFile(source, toPath(source), isDefaultLib, ignoreNoDefaultLib, refFile, packageId) :
2279+
undefined;
2280+
if (file) addFileToFilesByName(file, path, /*redirectedPath*/ undefined);
2281+
return file;
2282+
}
2283+
}
22372284
const originalFileName = fileName;
22382285
if (filesByName.has(path)) {
22392286
const file = filesByName.get(path);
@@ -2282,7 +2329,7 @@ namespace ts {
22822329
}
22832330

22842331
let redirectedPath: Path | undefined;
2285-
if (refFile) {
2332+
if (refFile && !useSourceOfProjectReferenceRedirect) {
22862333
const redirectProject = getProjectReferenceRedirectProject(fileName);
22872334
if (redirectProject) {
22882335
if (redirectProject.commandLine.options.outFile || redirectProject.commandLine.options.out) {
@@ -2451,6 +2498,36 @@ namespace ts {
24512498
});
24522499
}
24532500

2501+
function getSourceOfProjectReferenceRedirect(file: string) {
2502+
if (!isDeclarationFileName(file)) return undefined;
2503+
if (mapFromToProjectReferenceRedirectSource === undefined) {
2504+
mapFromToProjectReferenceRedirectSource = createMap();
2505+
forEachResolvedProjectReference(resolvedRef => {
2506+
if (resolvedRef) {
2507+
const out = resolvedRef.commandLine.options.outFile || resolvedRef.commandLine.options.out;
2508+
if (out) {
2509+
// Dont know which source file it means so return true?
2510+
const outputDts = changeExtension(out, Extension.Dts);
2511+
mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), true);
2512+
}
2513+
else {
2514+
forEach(resolvedRef.commandLine.fileNames, fileName => {
2515+
if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) {
2516+
const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, host.useCaseSensitiveFileNames());
2517+
mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName);
2518+
}
2519+
});
2520+
}
2521+
}
2522+
});
2523+
}
2524+
return mapFromToProjectReferenceRedirectSource.get(toPath(file));
2525+
}
2526+
2527+
function isSourceOfProjectReferenceRedirect(fileName: string) {
2528+
return useSourceOfProjectReferenceRedirect && !!getResolvedProjectReferenceToRedirect(fileName);
2529+
}
2530+
24542531
function forEachProjectReference<T>(
24552532
projectReferences: readonly ProjectReference[] | undefined,
24562533
resolvedProjectReferences: readonly (ResolvedProjectReference | undefined)[] | undefined,
@@ -2858,8 +2935,7 @@ namespace ts {
28582935
const rootPaths = arrayToSet(rootNames, toPath);
28592936
for (const file of files) {
28602937
// Ignore file that is not emitted
2861-
if (!sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect)) continue;
2862-
if (!rootPaths.has(file.path)) {
2938+
if (isValidSourceFileForEmit(file) && !rootPaths.has(file.path)) {
28632939
addProgramDiagnosticAtRefPath(
28642940
file,
28652941
rootPaths,

src/compiler/sys.ts

+28-19
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,33 @@ namespace ts {
522522
}
523523
}
524524

525+
function recursiveCreateDirectory(directoryPath: string, sys: System) {
526+
const basePath = getDirectoryPath(directoryPath);
527+
const shouldCreateParent = basePath !== "" && directoryPath !== basePath && !sys.directoryExists(basePath);
528+
if (shouldCreateParent) {
529+
recursiveCreateDirectory(basePath, sys);
530+
}
531+
if (shouldCreateParent || !sys.directoryExists(directoryPath)) {
532+
sys.createDirectory(directoryPath);
533+
}
534+
}
535+
536+
/**
537+
* patch writefile to create folder before writing the file
538+
*/
539+
/*@internal*/
540+
export function patchWriteFileEnsuringDirectory(sys: System) {
541+
// patch writefile to create folder before writing the file
542+
const originalWriteFile = sys.writeFile;
543+
sys.writeFile = (path, data, writeBom) => {
544+
const directoryPath = getDirectoryPath(normalizeSlashes(path));
545+
if (directoryPath && !sys.directoryExists(directoryPath)) {
546+
recursiveCreateDirectory(directoryPath, sys);
547+
}
548+
originalWriteFile.call(sys, path, data, writeBom);
549+
};
550+
}
551+
525552
/*@internal*/
526553
export type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex";
527554

@@ -1365,17 +1392,6 @@ namespace ts {
13651392
};
13661393
}
13671394

1368-
function recursiveCreateDirectory(directoryPath: string, sys: System) {
1369-
const basePath = getDirectoryPath(directoryPath);
1370-
const shouldCreateParent = basePath !== "" && directoryPath !== basePath && !sys.directoryExists(basePath);
1371-
if (shouldCreateParent) {
1372-
recursiveCreateDirectory(basePath, sys);
1373-
}
1374-
if (shouldCreateParent || !sys.directoryExists(directoryPath)) {
1375-
sys.createDirectory(directoryPath);
1376-
}
1377-
}
1378-
13791395
let sys: System | undefined;
13801396
if (typeof ChakraHost !== "undefined") {
13811397
sys = getChakraSystem();
@@ -1387,14 +1403,7 @@ namespace ts {
13871403
}
13881404
if (sys) {
13891405
// patch writefile to create folder before writing the file
1390-
const originalWriteFile = sys.writeFile;
1391-
sys.writeFile = (path, data, writeBom) => {
1392-
const directoryPath = getDirectoryPath(normalizeSlashes(path));
1393-
if (directoryPath && !sys!.directoryExists(directoryPath)) {
1394-
recursiveCreateDirectory(directoryPath, sys!);
1395-
}
1396-
originalWriteFile.call(sys, path, data, writeBom);
1397-
};
1406+
patchWriteFileEnsuringDirectory(sys);
13981407
}
13991408
return sys!;
14001409
})();

src/compiler/types.ts

+15
Original file line numberDiff line numberDiff line change
@@ -3065,6 +3065,7 @@ namespace ts {
30653065
/*@internal*/ getResolvedProjectReferenceToRedirect(fileName: string): ResolvedProjectReference | undefined;
30663066
/*@internal*/ forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined): T | undefined;
30673067
/*@internal*/ getResolvedProjectReferenceByPath(projectReferencePath: Path): ResolvedProjectReference | undefined;
3068+
/*@internal*/ isSourceOfProjectReferenceRedirect(fileName: string): boolean;
30683069
/*@internal*/ getProgramBuildInfo?(): ProgramBuildInfo | undefined;
30693070
/*@internal*/ emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
30703071
}
@@ -3165,6 +3166,7 @@ namespace ts {
31653166
getSourceFile(fileName: string): SourceFile | undefined;
31663167
getResolvedTypeReferenceDirectives(): ReadonlyMap<ResolvedTypeReferenceDirective | undefined>;
31673168
getProjectReferenceRedirect(fileName: string): string | undefined;
3169+
isSourceOfProjectReferenceRedirect(fileName: string): boolean;
31683170

31693171
readonly redirectTargetsMap: RedirectTargetsMap;
31703172
}
@@ -4775,6 +4777,7 @@ namespace ts {
47754777
/* @internal */ diagnostics?: boolean;
47764778
/* @internal */ extendedDiagnostics?: boolean;
47774779
disableSizeLimit?: boolean;
4780+
disableSourceOfProjectReferenceRedirect?: boolean;
47784781
downlevelIteration?: boolean;
47794782
emitBOM?: boolean;
47804783
emitDecoratorMetadata?: boolean;
@@ -5303,11 +5306,23 @@ namespace ts {
53035306
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
53045307
createHash?(data: string): string;
53055308
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
5309+
/* @internal */ setResolvedProjectReferenceCallbacks?(callbacks: ResolvedProjectReferenceCallbacks): void;
5310+
/* @internal */ useSourceOfProjectReferenceRedirect?(): boolean;
53065311

53075312
// TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesn't use compilerHost as base
53085313
/*@internal*/createDirectory?(directory: string): void;
53095314
}
53105315

5316+
/** true if --out otherwise source file name */
5317+
/*@internal*/
5318+
export type SourceOfProjectReferenceRedirect = string | true;
5319+
5320+
/*@internal*/
5321+
export interface ResolvedProjectReferenceCallbacks {
5322+
getSourceOfProjectReferenceRedirect(fileName: string): SourceOfProjectReferenceRedirect | undefined;
5323+
forEachResolvedProjectReference<T>(cb: (resolvedProjectReference: ResolvedProjectReference | undefined, resolvedProjectReferencePath: Path) => T | undefined): T | undefined;
5324+
}
5325+
53115326
/* @internal */
53125327
export const enum TransformFlags {
53135328
None = 0,

0 commit comments

Comments
 (0)