Skip to content

Commit 0c4003e

Browse files
committed
Use SolutionBuilderHost instead of using compilerhost for solution builder
1 parent dade336 commit 0c4003e

File tree

8 files changed

+47
-58
lines changed

8 files changed

+47
-58
lines changed

src/compiler/program.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,7 @@ namespace ts {
189189
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
190190
getDirectories: (path: string) => system.getDirectories(path),
191191
realpath,
192-
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth),
193-
getModifiedTime: system.getModifiedTime && (path => system.getModifiedTime!(path)),
194-
setModifiedTime: system.setModifiedTime && ((path, date) => system.setModifiedTime!(path, date)),
195-
deleteFile: system.deleteFile && (path => system.deleteFile!(path))
192+
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth)
196193
};
197194
}
198195

src/compiler/tsbuild.ts

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -388,16 +388,27 @@ namespace ts {
388388
};
389389
}
390390

391+
export interface SolutionBuilderHost extends CompilerHost {
392+
getModifiedTime(fileName: string): Date | undefined;
393+
setModifiedTime(fileName: string, date: Date): void;
394+
deleteFile(fileName: string): void;
395+
}
396+
397+
export function createSolutionBuilderHost(system = sys) {
398+
const host = createCompilerHost({}, /*setParentNodes*/ undefined, system) as SolutionBuilderHost;
399+
host.getModifiedTime = system.getModifiedTime ? path => system.getModifiedTime!(path) : () => undefined;
400+
host.setModifiedTime = system.setModifiedTime ? (path, date) => system.setModifiedTime!(path, date) : noop;
401+
host.deleteFile = system.deleteFile ? path => system.deleteFile!(path) : noop;
402+
return host;
403+
}
404+
391405
/**
392406
* A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but
393407
* can dynamically add/remove other projects based on changes on the rootNames' references
394408
*/
395-
export function createSolutionBuilder(compilerHost: CompilerHost, buildHost: BuildHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions, system?: System) {
396-
if (!compilerHost.getModifiedTime || !compilerHost.setModifiedTime) {
397-
throw new Error("Host must support timestamp APIs");
398-
}
409+
export function createSolutionBuilder(host: SolutionBuilderHost, buildHost: BuildHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions, system?: System) {
399410

400-
const configFileCache = createConfigFileCache(compilerHost);
411+
const configFileCache = createConfigFileCache(host);
401412
let context = createBuildContext(defaultOptions);
402413

403414
const existingWatchersForWildcards = createMap<WildcardDirectoryWatcher>();
@@ -501,14 +512,14 @@ namespace ts {
501512
let newestInputFileTime = minimumDate;
502513
// Get timestamps of input files
503514
for (const inputFile of project.fileNames) {
504-
if (!compilerHost.fileExists(inputFile)) {
515+
if (!host.fileExists(inputFile)) {
505516
return {
506517
type: UpToDateStatusType.Unbuildable,
507518
reason: `${inputFile} does not exist`
508519
};
509520
}
510521

511-
const inputTime = compilerHost.getModifiedTime!(inputFile) || missingFileModifiedTime;
522+
const inputTime = host.getModifiedTime(inputFile) || missingFileModifiedTime;
512523
if (inputTime > newestInputFileTime) {
513524
newestInputFileName = inputFile;
514525
newestInputFileTime = inputTime;
@@ -535,12 +546,12 @@ namespace ts {
535546
for (const output of outputs) {
536547
// Output is missing; can stop checking
537548
// Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
538-
if (!compilerHost.fileExists(output)) {
549+
if (!host.fileExists(output)) {
539550
missingOutputFileName = output;
540551
break;
541552
}
542553

543-
const outputTime = compilerHost.getModifiedTime!(output) || missingFileModifiedTime;
554+
const outputTime = host.getModifiedTime(output) || missingFileModifiedTime;
544555
if (outputTime < oldestOutputFileTime) {
545556
oldestOutputFileTime = outputTime;
546557
oldestOutputFileName = output;
@@ -568,7 +579,7 @@ namespace ts {
568579
newestDeclarationFileContentChangedTime = newer(unchangedTime, newestDeclarationFileContentChangedTime);
569580
}
570581
else {
571-
const outputModifiedTime = compilerHost.getModifiedTime!(output) || missingFileModifiedTime;
582+
const outputModifiedTime = host.getModifiedTime(output) || missingFileModifiedTime;
572583
newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, outputModifiedTime);
573584
}
574585
}
@@ -580,7 +591,7 @@ namespace ts {
580591
if (project.projectReferences) {
581592
for (const ref of project.projectReferences) {
582593
usesPrepend = usesPrepend || !!(ref.prepend);
583-
const resolvedRef = resolveProjectReferencePath(compilerHost, ref);
594+
const resolvedRef = resolveProjectReferencePath(host, ref);
584595
const refStatus = getUpToDateStatus(configFileCache.parseConfigFile(resolvedRef));
585596

586597
// An upstream project is blocked
@@ -809,7 +820,7 @@ namespace ts {
809820

810821
const programOptions: CreateProgramOptions = {
811822
projectReferences: configFile.projectReferences,
812-
host: compilerHost,
823+
host,
813824
rootNames: configFile.fileNames,
814825
options: configFile.options
815826
};
@@ -858,18 +869,18 @@ namespace ts {
858869
program.emit(/*targetSourceFile*/ undefined, (fileName, content, writeBom, onError) => {
859870
let priorChangeTime: Date | undefined;
860871

861-
if (!anyDtsChanged && isDeclarationFile(fileName) && compilerHost.fileExists(fileName)) {
862-
if (compilerHost.readFile(fileName) === content) {
872+
if (!anyDtsChanged && isDeclarationFile(fileName) && host.fileExists(fileName)) {
873+
if (host.readFile(fileName) === content) {
863874
// Check for unchanged .d.ts files
864875
resultFlags &= ~BuildResultFlags.DeclarationOutputUnchanged;
865-
priorChangeTime = compilerHost.getModifiedTime && compilerHost.getModifiedTime(fileName);
876+
priorChangeTime = host.getModifiedTime(fileName);
866877
}
867878
else {
868879
anyDtsChanged = true;
869880
}
870881
}
871882

872-
compilerHost.writeFile(fileName, content, writeBom, onError, emptyArray);
883+
host.writeFile(fileName, content, writeBom, onError, emptyArray);
873884
if (priorChangeTime !== undefined) {
874885
newestDeclarationFileContentChangedTime = newer(priorChangeTime, newestDeclarationFileContentChangedTime);
875886
context.unchangedOutputs.setValue(fileName, priorChangeTime);
@@ -898,10 +909,10 @@ namespace ts {
898909
let priorNewestUpdateTime = minimumDate;
899910
for (const file of outputs) {
900911
if (isDeclarationFile(file)) {
901-
priorNewestUpdateTime = newer(priorNewestUpdateTime, compilerHost.getModifiedTime!(file) || missingFileModifiedTime);
912+
priorNewestUpdateTime = newer(priorNewestUpdateTime, host.getModifiedTime(file) || missingFileModifiedTime);
902913
}
903914

904-
compilerHost.setModifiedTime!(file, now);
915+
host.setModifiedTime(file, now);
905916
}
906917

907918
context.projectStatus.setValue(proj.options.configFilePath!, { type: UpToDateStatusType.UpToDate, newestDeclarationFileContentChangedTime: priorNewestUpdateTime } as UpToDateStatus);
@@ -924,7 +935,7 @@ namespace ts {
924935
}
925936
const outputs = getAllProjectOutputs(parsed);
926937
for (const output of outputs) {
927-
if (compilerHost.fileExists(output)) {
938+
if (host.fileExists(output)) {
928939
filesToDelete.push(output);
929940
}
930941
}
@@ -958,25 +969,20 @@ namespace ts {
958969
return ExitStatus.Success;
959970
}
960971

961-
// Do this check later to allow --clean --dry to function even if the host can't delete files
962-
if (!compilerHost.deleteFile) {
963-
throw new Error("Host does not support deleting files");
964-
}
965-
966972
for (const output of filesToDelete) {
967-
compilerHost.deleteFile(output);
973+
host.deleteFile(output);
968974
}
969975

970976
return ExitStatus.Success;
971977
}
972978

973979
function resolveProjectName(name: string): ResolvedConfigFileName | undefined {
974-
const fullPath = resolvePath(compilerHost.getCurrentDirectory(), name);
975-
if (compilerHost.fileExists(fullPath)) {
980+
const fullPath = resolvePath(host.getCurrentDirectory(), name);
981+
if (host.fileExists(fullPath)) {
976982
return fullPath as ResolvedConfigFileName;
977983
}
978984
const fullPathWithTsconfig = combinePaths(fullPath, "tsconfig.json");
979-
if (compilerHost.fileExists(fullPathWithTsconfig)) {
985+
if (host.fileExists(fullPathWithTsconfig)) {
980986
return fullPathWithTsconfig as ResolvedConfigFileName;
981987
}
982988
buildHost.error(Diagnostics.File_0_not_found, relName(fullPath));
@@ -1058,7 +1064,7 @@ namespace ts {
10581064
}
10591065

10601066
function relName(path: string): string {
1061-
return convertToRelativePath(path, compilerHost.getCurrentDirectory(), f => compilerHost.getCanonicalFileName(f));
1067+
return convertToRelativePath(path, host.getCurrentDirectory(), f => host.getCanonicalFileName(f));
10621068
}
10631069

10641070
function reportVerbose(message: DiagnosticMessage, ...args: string[]) {
@@ -1074,15 +1080,6 @@ namespace ts {
10741080
}
10751081
}
10761082

1077-
export interface UpToDateHost {
1078-
fileExists(fileName: string): boolean;
1079-
getModifiedTime(fileName: string): Date | undefined;
1080-
getUnchangedTime?(fileName: string): Date | undefined;
1081-
getLastStatus?(fileName: string): UpToDateStatus | undefined;
1082-
setLastStatus?(fileName: string, status: UpToDateStatus): void;
1083-
parseConfigFile?(configFilePath: ResolvedConfigFileName): ParsedCommandLine | undefined;
1084-
}
1085-
10861083
export function getAllProjectOutputs(project: ParsedCommandLine): ReadonlyArray<string> {
10871084
if (project.options.outFile) {
10881085
return getOutFileOutputs(project);

src/compiler/types.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4845,10 +4845,6 @@ namespace ts {
48454845
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
48464846
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
48474847
createHash?(data: string): string;
4848-
4849-
getModifiedTime?(fileName: string): Date | undefined;
4850-
setModifiedTime?(fileName: string, date: Date): void;
4851-
deleteFile?(fileName: string): void;
48524848
}
48534849

48544850
/* @internal */

src/harness/fakes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ namespace fakes {
205205
/**
206206
* A fake `ts.CompilerHost` that leverages a virtual file system.
207207
*/
208-
export class CompilerHost implements ts.CompilerHost {
208+
export class CompilerHost implements ts.CompilerHost, ts.SolutionBuilderHost {
209209
public readonly sys: System;
210210
public readonly defaultLibLocation: string;
211211
public readonly outputs: documents.TextDocument[] = [];

src/testRunner/unittests/tsbuildWatchMode.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
namespace ts.tscWatch {
22
export import libFile = TestFSWithWatch.libFile;
3-
function createSolutionBuilder(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
4-
const compilerHost = createCompilerHost({}, /*setParentNodes*/ undefined, host);
5-
const reportDiag = createDiagnosticReporter(host);
3+
function createSolutionBuilder(system: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {
4+
const host = createSolutionBuilderHost(system);
5+
const reportDiag = createDiagnosticReporter(system);
66
const report = (message: DiagnosticMessage, ...args: string[]) => reportDiag(createCompilerDiagnostic(message, ...args));
77
const buildHost: BuildHost = {
88
error: report,
99
verbose: report,
1010
message: report,
1111
errorDiagnostic: d => reportDiag(d)
1212
};
13-
return ts.createSolutionBuilder(compilerHost, buildHost, rootNames, defaultOptions || { dry: false, force: false, verbose: false }, host);
13+
return ts.createSolutionBuilder(host, buildHost, rootNames, defaultOptions || { dry: false, force: false, verbose: false }, system);
1414
}
1515

1616
function createSolutionBuilderWithWatch(host: WatchedSystem, rootNames: ReadonlyArray<string>, defaultOptions?: BuildOptions) {

src/tsc/tsc.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ namespace ts {
243243
// Update to pretty if host supports it
244244
updateReportDiagnostic({});
245245

246+
if (!sys.getModifiedTime || !sys.setModifiedTime || (buildOptions.clean && !sys.deleteFile)) {
247+
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--build"));
248+
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
249+
}
250+
246251
// Nonsensical combinations
247252
if (buildOptions.clean && buildOptions.force) {
248253
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
@@ -274,7 +279,7 @@ namespace ts {
274279
errorDiagnostic: d => reportDiagnostic(d)
275280
};
276281

277-
const builder = createSolutionBuilder(createCompilerHost({}), buildHost, projects, buildOptions);
282+
const builder = createSolutionBuilder(createSolutionBuilderHost(), buildHost, projects, buildOptions);
278283
if (buildOptions.clean) {
279284
return builder.cleanAllProjects();
280285
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,9 +2690,6 @@ declare namespace ts {
26902690
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
26912691
getEnvironmentVariable?(name: string): string | undefined;
26922692
createHash?(data: string): string;
2693-
getModifiedTime?(fileName: string): Date | undefined;
2694-
setModifiedTime?(fileName: string, date: Date): void;
2695-
deleteFile?(fileName: string): void;
26962693
}
26972694
interface SourceMapRange extends TextRange {
26982695
source?: SourceMapSource;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,9 +2690,6 @@ declare namespace ts {
26902690
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
26912691
getEnvironmentVariable?(name: string): string | undefined;
26922692
createHash?(data: string): string;
2693-
getModifiedTime?(fileName: string): Date | undefined;
2694-
setModifiedTime?(fileName: string, date: Date): void;
2695-
deleteFile?(fileName: string): void;
26962693
}
26972694
interface SourceMapRange extends TextRange {
26982695
source?: SourceMapSource;

0 commit comments

Comments
 (0)