From 021444a248dfd688866b482ba83f48b7df3769e4 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 26 Mar 2019 13:37:51 -0700 Subject: [PATCH] Make it as api so we can test it --- src/compiler/program.ts | 7 +- src/compiler/watch.ts | 50 ++++++++++++ .../unittests/tscWatch/incremental.ts | 76 +++++++++++++++---- src/tsc/tsc.ts | 34 ++------- 4 files changed, 118 insertions(+), 49 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 65e8fc81d9f..b188e708a62 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -74,12 +74,7 @@ namespace ts { // TODO(shkamat): update this after reworking ts build API export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost { const existingDirectories = createMap(); - function getCanonicalFileName(fileName: string): string { - // if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form. - // otherwise use toLowerCase as a canonical form. - return system.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); - } - + const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames); function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined { let text: string | undefined; try { diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 6206c22eeba..d4147b6873e 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -383,6 +383,56 @@ namespace ts { if (!buildInfo.program) return undefined; return createBuildProgramUsingProgramBuildInfo(buildInfo.program); } + + export function createIncrementalCompilerHost(options: CompilerOptions, system = sys): CompilerHost { + const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, system); + host.createHash = maybeBind(system, system.createHash); + setGetSourceFileAsHashVersioned(host, system); + changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName)); + return host; + } + + export interface IncrementalProgramOptions { + rootNames: ReadonlyArray; + options: CompilerOptions; + configFileParsingDiagnostics?: ReadonlyArray; + projectReferences?: ReadonlyArray; + host?: CompilerHost; + createProgram?: CreateProgram; + } + export function createIncrementalProgram({ + rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram + }: IncrementalProgramOptions): T { + host = host || createIncrementalCompilerHost(options); + createProgram = createProgram || createEmitAndSemanticDiagnosticsBuilderProgram as any as CreateProgram; + const oldProgram = readBuilderProgram(options, path => host!.readFile(path)) as any as T; + return createProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences); + } + + export interface IncrementalCompilationOptions { + rootNames: ReadonlyArray; + options: CompilerOptions; + configFileParsingDiagnostics?: ReadonlyArray; + projectReferences?: ReadonlyArray; + host?: CompilerHost; + reportDiagnostic?: DiagnosticReporter; + reportErrorSummary?: ReportEmitErrorSummary; + afterProgramEmitAndDiagnostics?(program: EmitAndSemanticDiagnosticsBuilderProgram): void; + system?: System; + } + export function performIncrementalCompilation(input: IncrementalCompilationOptions) { + const system = input.system || sys; + const host = input.host || (input.host = createIncrementalCompilerHost(input.options, system)); + const builderProgram = createIncrementalProgram(input); + const exitStatus = emitFilesAndReportErrors( + builderProgram, + input.reportDiagnostic || createDiagnosticReporter(system), + s => host!.trace && host!.trace!(s), + input.reportErrorSummary || input.options.pretty ? errorCount => system.write(getErrorSummaryText(errorCount, system.newLine)) : undefined + ); + if (input.afterProgramEmitAndDiagnostics) input.afterProgramEmitAndDiagnostics(builderProgram); + return exitStatus; + } } namespace ts { diff --git a/src/testRunner/unittests/tscWatch/incremental.ts b/src/testRunner/unittests/tscWatch/incremental.ts index f21f994914c..c384f74ddce 100644 --- a/src/testRunner/unittests/tscWatch/incremental.ts +++ b/src/testRunner/unittests/tscWatch/incremental.ts @@ -15,9 +15,35 @@ namespace ts.tscWatch { expectedIncrementalEmit?: ReadonlyArray; expectedIncrementalErrors?: ReadonlyArray; } - function verifyIncrementalWatchEmit({ - files, expectedInitialEmit, expectedInitialErrors, modifyFs, expectedIncrementalEmit, expectedIncrementalErrors - }: VerifyIncrementalWatchEmitInput) { + function verifyIncrementalWatchEmit(input: VerifyIncrementalWatchEmitInput) { + it("with tsc --w", () => { + verifyIncrementalWatchEmitWorker({ + input, + emitAndReportErrors: createWatchOfConfigFile, + verifyErrors: checkOutputErrorsInitial + }); + }); + it("with tsc", () => { + verifyIncrementalWatchEmitWorker({ + input, + emitAndReportErrors: , + verifyErrors + }); + }); + } + + interface VerifyIncrementalWatchEmitWorkerInput { + input: VerifyIncrementalWatchEmitInput; + emitAndReportErrors: (configFile: string, host: WatchedSystem) => { close(): void; }; + verifyErrors: (host: WatchedSystem, errors: ReadonlyArray) => void; + } + function verifyIncrementalWatchEmitWorker({ + input: { + files, expectedInitialEmit, expectedInitialErrors, modifyFs, expectedIncrementalEmit, expectedIncrementalErrors + }, + emitAndReportErrors, + verifyErrors + }: VerifyIncrementalWatchEmitWorkerInput) { const host = createWatchedSystem(files, { currentDirectory: project }); const originalWriteFile = host.writeFile; const writtenFiles = createMap(); @@ -26,18 +52,40 @@ namespace ts.tscWatch { writtenFiles.set(path, content); originalWriteFile.call(host, path, content); }; - verifyWatch(host, writtenFiles, expectedInitialEmit, expectedInitialErrors); + verifyBuild({ + host, + writtenFiles, + emitAndReportErrors, + verifyErrors, + expectedEmit: expectedInitialEmit, + expectedErrors: expectedInitialErrors + }); if (modifyFs) { modifyFs(host); - verifyWatch(host, writtenFiles, Debug.assertDefined(expectedIncrementalEmit), Debug.assertDefined(expectedIncrementalErrors)); + verifyBuild({ + host, + writtenFiles, + emitAndReportErrors, + verifyErrors, + expectedEmit: Debug.assertDefined(expectedIncrementalEmit), + expectedErrors: Debug.assertDefined(expectedIncrementalErrors) + }); } } - function verifyWatch(host: WatchedSystem, writtenFiles: Map, expectedEmit: ReadonlyArray, expectedErrors: ReadonlyArray) { + interface VerifyBuildWorker { + host: WatchedSystem; + writtenFiles: Map; + emitAndReportErrors: VerifyIncrementalWatchEmitWorkerInput["emitAndReportErrors"]; + verifyErrors: VerifyIncrementalWatchEmitWorkerInput["verifyErrors"]; + expectedEmit: ReadonlyArray; + expectedErrors: ReadonlyArray; + } + function verifyBuild({ host, writtenFiles, emitAndReportErrors, verifyErrors, expectedEmit, expectedErrors }: VerifyBuildWorker) { writtenFiles.clear(); - const watch = createWatchOfConfigFile("tsconfig.json", host); + const watch = emitAndReportErrors("tsconfig.json", host); checkFileEmit(writtenFiles, expectedEmit); - checkOutputErrorsInitial(host, expectedErrors); + verifyErrors(host, expectedErrors); watch.close(); } @@ -73,7 +121,7 @@ namespace ts.tscWatch { content: "var y = 20;\n" }; - it("own file emit without errors", () => { + describe("own file emit without errors", () => { const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10"); verifyIncrementalWatchEmit({ files: [libFile, file1, file2, configFile], @@ -125,7 +173,7 @@ namespace ts.tscWatch { }); }); - it("own file emit with errors", () => { + describe("own file emit with errors", () => { const fileModified: File = { path: file2.path, content: `const y: string = 20;` @@ -208,7 +256,7 @@ namespace ts.tscWatch { }); }); - it("with --out", () => { + describe("with --out", () => { const config: File = { path: configFile.path, content: JSON.stringify({ compilerOptions: { incremental: true, outFile: "out.js" } }) @@ -279,7 +327,7 @@ namespace ts.tscWatch { content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd" } }) }; - it("own file emit without errors", () => { + describe("own file emit without errors", () => { const modifiedFile2Content = file2.content.replace("y", "z").replace("20", "10"); verifyIncrementalWatchEmit({ files: [libFile, file1, file2, config], @@ -330,7 +378,7 @@ namespace ts.tscWatch { }); }); - it("own file emit with errors", () => { + describe("own file emit with errors", () => { const fileModified: File = { path: file2.path, content: `export const y: string = 20;` @@ -412,7 +460,7 @@ namespace ts.tscWatch { }); }); - it("with --out", () => { + describe("with --out", () => { const config: File = { path: configFile.path, content: JSON.stringify({ compilerOptions: { incremental: true, module: "amd", outFile: "out.js" } }) diff --git a/src/tsc/tsc.ts b/src/tsc/tsc.ts index 31b5d7d75d8..6a81cb09ab7 100644 --- a/src/tsc/tsc.ts +++ b/src/tsc/tsc.ts @@ -260,40 +260,16 @@ namespace ts { function performIncrementalCompilation(config: ParsedCommandLine) { const { options, fileNames, projectReferences } = config; - const host = createCompilerHost(options); - const currentDirectory = host.getCurrentDirectory(); - const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames()); - setGetSourceFileAsHashVersioned(host, sys); - changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName)); enableStatistics(options); - const oldProgram = readBuilderProgram(options, path => host.readFile(path)); - const configFileParsingDiagnostics = getConfigFileParsingDiagnostics(config); - const programOptions: CreateProgramOptions = { + const exitStatus = ts.performIncrementalCompilation({ rootNames: fileNames, options, - projectReferences, - host, configFileParsingDiagnostics: getConfigFileParsingDiagnostics(config), - }; - const program = createProgram(programOptions); - const builderProgram = createEmitAndSemanticDiagnosticsBuilderProgram( - program, - { - useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames, - createHash: maybeBind(sys, sys.createHash), - writeFile: (path, data, writeByteOrderMark) => sys.writeFile(path, data, writeByteOrderMark) - }, - oldProgram, - configFileParsingDiagnostics - ); - - const exitStatus = emitFilesAndReportErrors( - builderProgram, + projectReferences, reportDiagnostic, - s => sys.write(s + sys.newLine), - createReportErrorSummary(options) - ); - reportStatistics(program); + reportErrorSummary: createReportErrorSummary(options), + afterProgramEmitAndDiagnostics: builderProgram => reportStatistics(builderProgram.getProgram()) + }); return sys.exit(exitStatus); }