From 5a2fb94a955d03847e82a06b9c77ea1328d54f32 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 16 Dec 2014 14:42:58 -0800 Subject: [PATCH] Clean things up so the services layer can easily emit without having to contort compiler hosts. --- src/compiler/emitter.ts | 37 +++++++++++++++++-------------------- src/compiler/program.ts | 10 ++++++++-- src/compiler/types.ts | 22 ++++++++++++++-------- src/compiler/utilities.ts | 18 ++++++++++++++++-- src/services/services.ts | 15 ++++++--------- 5 files changed, 61 insertions(+), 41 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 7b20fb8e216..d349a9b626d 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -313,8 +313,7 @@ module ts { } function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) { - var compilerHost = host.getCompilerHost(); - var sourceFilePath = getNormalizedAbsolutePath(sourceFile.filename, compilerHost.getCurrentDirectory()); + var sourceFilePath = getNormalizedAbsolutePath(sourceFile.filename, host.getCurrentDirectory()); sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), ""); return combinePaths(newDirPath, sourceFilePath); } @@ -331,16 +330,15 @@ module ts { return emitOutputFilePathWithoutExtension + extension; } - function writeFile(compilerHost: CompilerHost, diagnostics: Diagnostic[], filename: string, data: string, writeByteOrderMark: boolean) { - compilerHost.writeFile(filename, data, writeByteOrderMark, hostErrorMessage => { + function writeFile(host: EmitHost, diagnostics: Diagnostic[], filename: string, data: string, writeByteOrderMark: boolean) { + host.writeFile(filename, data, writeByteOrderMark, hostErrorMessage => { diagnostics.push(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, filename, hostErrorMessage)); }); } function emitDeclarations(host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit { - var newLine = host.getCompilerHost().getNewLine(); + var newLine = host.getNewLine(); var compilerOptions = host.getCompilerOptions(); - var compilerHost = host.getCompilerHost(); var write: (s: string) => void; var writeLine: () => void; @@ -1402,8 +1400,8 @@ module ts { declFileName = getRelativePathToDirectoryOrUrl( getDirectoryPath(normalizeSlashes(jsFilePath)), declFileName, - compilerHost.getCurrentDirectory(), - compilerHost.getCanonicalFileName, + host.getCurrentDirectory(), + host.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); referencePathsOutput += "/// " + newLine; @@ -1464,21 +1462,20 @@ module ts { } } - export function getDeclarationDiagnostics(program: Program, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] { + export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] { var diagnostics: Diagnostic[] = []; - var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, program, ".js"); - emitDeclarations(program, resolver, diagnostics, jsFilePath, targetSourceFile); + var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js"); + emitDeclarations(host, resolver, diagnostics, jsFilePath, targetSourceFile); return diagnostics; } // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compilerOnSave feature export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile?: SourceFile): EmitResult { // var program = resolver.getProgram(); - var compilerHost = host.getCompilerHost(); var compilerOptions = host.getCompilerOptions(); var sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined; var diagnostics: Diagnostic[] = []; - var newLine = compilerHost.getNewLine(); + var newLine = host.getNewLine(); function emitJavaScript(jsFilePath: string, root?: SourceFile) { var writer = createTextWriter(newLine); @@ -1704,8 +1701,8 @@ module ts { sourceMapData.sourceMapSources.push(getRelativePathToDirectoryOrUrl(sourcesDirectoryPath, node.filename, - compilerHost.getCurrentDirectory(), - compilerHost.getCanonicalFileName, + host.getCurrentDirectory(), + host.getCanonicalFileName, /*isAbsolutePathAnUrl*/ true)); sourceMapSourceIndex = sourceMapData.sourceMapSources.length - 1; @@ -1801,7 +1798,7 @@ module ts { function writeJavaScriptAndSourceMapFile(emitOutput: string, writeByteOrderMark: boolean) { // Write source map file encodeLastRecordedSourceMapSpan(); - writeFile(compilerHost, diagnostics, sourceMapData.sourceMapFilePath, serializeSourceMapContents( + writeFile(host, diagnostics, sourceMapData.sourceMapFilePath, serializeSourceMapContents( 3, sourceMapData.sourceMapFile, sourceMapData.sourceMapSourceRoot, @@ -1849,8 +1846,8 @@ module ts { sourceMapData.jsSourceMappingURL = getRelativePathToDirectoryOrUrl( getDirectoryPath(normalizePath(jsFilePath)), // get the relative sourceMapDir path based on jsFilePath combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL), // this is where user expects to see sourceMap - compilerHost.getCurrentDirectory(), - compilerHost.getCanonicalFileName, + host.getCurrentDirectory(), + host.getCanonicalFileName, /*isAbsolutePathAnUrl*/ true); } else { @@ -1886,7 +1883,7 @@ module ts { } function writeJavaScriptFile(emitOutput: string, writeByteOrderMark: boolean) { - writeFile(compilerHost, diagnostics, jsFilePath, emitOutput, writeByteOrderMark); + writeFile(host, diagnostics, jsFilePath, emitOutput, writeByteOrderMark); } // Create a temporary variable with a unique unused name. The forLoopVariable parameter signals that the @@ -4128,7 +4125,7 @@ module ts { } }); declarationOutput += emitDeclarationResult.synchronousDeclarationOutput.substring(appliedSyncOutputPos); - writeFile(compilerHost, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, compilerOptions.emitBOM); + writeFile(host, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, compilerOptions.emitBOM); } } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 8d81ec45679..cc309646c8a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -91,6 +91,7 @@ module ts { var diagnosticsProducingTypeChecker: TypeChecker; var noDiagnosticsTypeChecker: TypeChecker; + var emitHost: EmitHost; program = { getSourceFile: getSourceFile, @@ -104,9 +105,14 @@ module ts { getCommonSourceDirectory: () => commonSourceDirectory, emitFiles: invokeEmitter, isEmitBlocked, + getCurrentDirectory: host.getCurrentDirectory, }; return program; + function getEmitHost() { + return emitHost || (emitHost = createEmitHostFromProgram(program)); + } + function hasEarlyErrors(sourceFile?: SourceFile): boolean { return forEach(getDiagnosticsProducingTypeChecker().getDiagnostics(sourceFile), d => d.isEarly); } @@ -134,12 +140,12 @@ module ts { var typeChecker = getDiagnosticsProducingTypeChecker(); typeChecker.getDiagnostics(targetSourceFile); var resolver = typeChecker.getEmitResolver(); - return ts.getDeclarationDiagnostics(program, resolver, targetSourceFile); + return ts.getDeclarationDiagnostics(getEmitHost(), resolver, targetSourceFile); } function invokeEmitter(targetSourceFile?: SourceFile) { var resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(); - return emitFiles(resolver, program, targetSourceFile); + return emitFiles(resolver, getEmitHost(), targetSourceFile); } function getSourceFile(filename: string) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0a00dff6d39..d606b40c0c8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -906,10 +906,8 @@ module ts { identifiers: Map; } - export interface Program { - getSourceFile(filename: string): SourceFile; + export interface Program extends ScriptReferenceHost { getSourceFiles(): SourceFile[]; - getCompilerOptions(): CompilerOptions; getCompilerHost(): CompilerHost; getDiagnostics(sourceFile?: SourceFile): Diagnostic[]; @@ -1102,13 +1100,21 @@ module ts { errorModuleName?: string // If the symbol is not visible from module, module's name } - export interface EmitHost { - getSourceFile(filename: string): SourceFile; - getSourceFiles(): SourceFile[]; - getCompilerHost(): CompilerHost; + export interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; - getCommonSourceDirectory(): string; + getSourceFile(filename: string): SourceFile; + getCurrentDirectory(): string; + } + + export interface EmitHost extends ScriptReferenceHost { + getSourceFiles(): SourceFile[]; isEmitBlocked(sourceFile?: SourceFile): boolean; + + getCommonSourceDirectory(): string; + getCanonicalFileName(fileName: string): string; + getNewLine(): string; + + writeFile(filename: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void): void; } export interface EmitResolver { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8aa04811143..1b9d9caf326 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -636,10 +636,10 @@ module ts { return undefined; } - export function tryResolveScriptReference(host: EmitHost, sourceFile: SourceFile, reference: FileReference) { + export function tryResolveScriptReference(host: ScriptReferenceHost, sourceFile: SourceFile, reference: FileReference) { if (!host.getCompilerOptions().noResolve) { var referenceFileName = isRootedDiskPath(reference.filename) ? reference.filename : combinePaths(getDirectoryPath(sourceFile.filename), reference.filename); - referenceFileName = getNormalizedAbsolutePath(referenceFileName, host.getCompilerHost().getCurrentDirectory()); + referenceFileName = getNormalizedAbsolutePath(referenceFileName, host.getCurrentDirectory()); return host.getSourceFile(referenceFileName); } } @@ -734,4 +734,18 @@ module ts { return false; } + export function createEmitHostFromProgram(program: Program): EmitHost { + var compilerHost = program.getCompilerHost(); + return { + getCanonicalFileName: compilerHost.getCanonicalFileName, + getCommonSourceDirectory: program.getCommonSourceDirectory, + getCompilerOptions: program.getCompilerOptions, + getCurrentDirectory: compilerHost.getCurrentDirectory, + getNewLine: compilerHost.getNewLine, + getSourceFile: program.getSourceFile, + getSourceFiles: program.getSourceFiles, + isEmitBlocked: program.isEmitBlocked, + writeFile: compilerHost.writeFile, + }; + } } \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index 7e8a4b3b6a8..adc15378594 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2224,7 +2224,6 @@ module ts { var documentRegistry = documentRegistry; var cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken()); var activeCompletionSession: CompletionSession; // The current active completion session, used to get the completion entry details - var writer: (filename: string, data: string, writeByteOrderMark: boolean) => void = undefined; // Check if the localized messages json is set, otherwise query the host for it if (!localizedDiagnosticMessages && host.getLocalizedDiagnosticMessages) { @@ -2267,7 +2266,6 @@ module ts { return host.getDefaultLibFilename(options); }, writeFile: (filename, data, writeByteOrderMark) => { - writer(filename, data, writeByteOrderMark); }, getCurrentDirectory: (): string => { return host.getCurrentDirectory(); @@ -4854,7 +4852,7 @@ module ts { var outputFiles: OutputFile[] = []; - function getEmitOutputWriter(filename: string, data: string, writeByteOrderMark: boolean) { + function writeFile(filename: string, data: string, writeByteOrderMark: boolean) { outputFiles.push({ name: filename, writeByteOrderMark: writeByteOrderMark, @@ -4862,13 +4860,12 @@ module ts { }); } - // Initialize writer for CompilerHost.writeFile - writer = getEmitOutputWriter; + // Get an emit host from our program, but override the writeFile functionality to + // call our local writer function. + var emitHost = createEmitHostFromProgram(program); + emitHost.writeFile = writeFile; - var emitOutput = program.emitFiles(sourceFile); - - // Reset writer back to undefined to make sure that we produce an error message if CompilerHost.writeFile method is called when we are not in getEmitOutput - writer = undefined; + var emitOutput = emitFiles(getDiagnosticsProducingTypeChecker().getEmitResolver(), emitHost, sourceFile); return { outputFiles,