Make it as api so we can test it

This commit is contained in:
Sheetal Nandi 2019-03-26 13:37:51 -07:00
parent e28869d888
commit 021444a248
4 changed files with 118 additions and 49 deletions

View File

@ -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<boolean>();
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 {

View File

@ -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<T extends BuilderProgram> {
rootNames: ReadonlyArray<string>;
options: CompilerOptions;
configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>;
projectReferences?: ReadonlyArray<ProjectReference>;
host?: CompilerHost;
createProgram?: CreateProgram<T>;
}
export function createIncrementalProgram<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>({
rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram
}: IncrementalProgramOptions<T>): T {
host = host || createIncrementalCompilerHost(options);
createProgram = createProgram || createEmitAndSemanticDiagnosticsBuilderProgram as any as CreateProgram<T>;
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<string>;
options: CompilerOptions;
configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>;
projectReferences?: ReadonlyArray<ProjectReference>;
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 {

View File

@ -15,9 +15,35 @@ namespace ts.tscWatch {
expectedIncrementalEmit?: ReadonlyArray<File>;
expectedIncrementalErrors?: ReadonlyArray<string>;
}
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<string>) => 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<string>();
@ -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<string>, expectedEmit: ReadonlyArray<File>, expectedErrors: ReadonlyArray<string>) {
interface VerifyBuildWorker {
host: WatchedSystem;
writtenFiles: Map<string>;
emitAndReportErrors: VerifyIncrementalWatchEmitWorkerInput["emitAndReportErrors"];
verifyErrors: VerifyIncrementalWatchEmitWorkerInput["verifyErrors"];
expectedEmit: ReadonlyArray<File>;
expectedErrors: ReadonlyArray<string>;
}
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" } })

View File

@ -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);
}