Simplifty declaration emitter logic by using forEachExpectedEmitFile

This commit is contained in:
Sheetal Nandi 2015-10-30 15:04:46 -07:00
parent 06bf08c17f
commit 2b582a0b71
3 changed files with 99 additions and 120 deletions

View File

@ -36,11 +36,12 @@ namespace ts {
return declarationDiagnostics.getDiagnostics(targetSourceFile.fileName);
function getDeclarationDiagnosticsFromFile({ declarationFilePath }, sources: SourceFile[], isBundledEmit: boolean) {
emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, !isBundledEmit ? targetSourceFile : undefined);
emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit);
}
}
function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string, root?: SourceFile): DeclarationEmit {
function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string,
sourceFiles: SourceFile[], isBundledEmit: boolean): DeclarationEmit {
let newLine = host.getNewLine();
let compilerOptions = host.getCompilerOptions();
@ -67,67 +68,48 @@ namespace ts {
// and we could be collecting these paths from multiple files into single one with --out option
let referencePathsOutput = "";
if (root) {
// Emitting just a single file, so emit references in this file only
if (!compilerOptions.noResolve) {
let addedGlobalFileReference = false;
forEach(root.referencedFiles, fileReference => {
let referencedFile = tryResolveScriptReference(host, root, fileReference);
// Emit references corresponding to each file
let emittedReferencedFiles: SourceFile[] = [];
let addedGlobalFileReference = false;
forEach(sourceFiles, sourceFile => {
if (!isJavaScript(sourceFile.fileName)) {
// Check what references need to be added
if (!compilerOptions.noResolve) {
forEach(sourceFile.referencedFiles, fileReference => {
let referencedFile = tryResolveScriptReference(host, sourceFile, fileReference);
// All the references that are not going to be part of same file
if (referencedFile && ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference
shouldEmitToOwnFile(referencedFile, compilerOptions) || // This is referenced file is emitting its own js file
!addedGlobalFileReference)) { // Or the global out file corresponding to this reference was not added
writeReferencePath(referencedFile);
if (!isExternalModuleOrDeclarationFile(referencedFile)) {
addedGlobalFileReference = true;
}
}
});
}
emitSourceFile(root);
// create asynchronous output for the importDeclarations
if (moduleElementDeclarationEmitInfo.length) {
let oldWriter = writer;
forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
if (aliasEmitInfo.isVisible) {
Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration);
createAndSetNewTextWriterWithSymbolWriter();
Debug.assert(aliasEmitInfo.indent === 0);
writeImportDeclaration(<ImportDeclaration>aliasEmitInfo.node);
aliasEmitInfo.asynchronousOutput = writer.getText();
}
});
setWriter(oldWriter);
}
}
else {
// Emit references corresponding to this file
let emittedReferencedFiles: SourceFile[] = [];
forEach(host.getSourceFiles(), sourceFile => {
if (!isExternalModuleOrDeclarationFile(sourceFile) && !isJavaScript(sourceFile.fileName)) {
// Check what references need to be added
if (!compilerOptions.noResolve) {
forEach(sourceFile.referencedFiles, fileReference => {
let referencedFile = tryResolveScriptReference(host, sourceFile, fileReference);
// If the reference file is a declaration file or an external module, emit that reference
if (referencedFile && (isExternalModuleOrDeclarationFile(referencedFile) &&
!contains(emittedReferencedFiles, referencedFile))) { // If the file reference was not already emitted
writeReferencePath(referencedFile);
emittedReferencedFiles.push(referencedFile);
// Emit reference in dts, if the file reference was not already emitted
if (referencedFile && !contains(emittedReferencedFiles, referencedFile)) {
// Add a reference to generated dts file,
// global file reference is added only
// - if it is not bundled emit (because otherwise it would be self reference)
// - and it is not already added
if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference)) {
addedGlobalFileReference = true;
}
});
}
emitSourceFile(sourceFile);
emittedReferencedFiles.push(referencedFile);
}
});
}
});
}
emitSourceFile(sourceFile);
// create asynchronous output for the importDeclarations
if (moduleElementDeclarationEmitInfo.length) {
let oldWriter = writer;
forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
if (aliasEmitInfo.isVisible) {
Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration);
createAndSetNewTextWriterWithSymbolWriter();
Debug.assert(aliasEmitInfo.indent === 0);
writeImportDeclaration(<ImportDeclaration>aliasEmitInfo.node);
aliasEmitInfo.asynchronousOutput = writer.getText();
}
});
setWriter(oldWriter);
}
}
});
return {
reportedDeclarationError,
@ -1592,33 +1574,51 @@ namespace ts {
}
}
function writeReferencePath(referencedFile: SourceFile) {
/**
* Adds the reference to referenced file, returns true if global file reference was emitted
* @param referencedFile
* @param addBundledFileReference Determines if global file reference corresponding to bundled file should be emitted or not
*/
function writeReferencePath(referencedFile: SourceFile, addBundledFileReference: boolean): boolean {
let declFileName: string;
if (referencedFile.flags & NodeFlags.DeclarationFile) {
let addedBundledEmitReference = false;
if (isDeclarationFile(referencedFile)) {
// Declaration file, use declaration file name
declFileName = referencedFile.fileName;
}
else {
// declaration file name
let { declarationFilePath, jsFilePath } = getEmitFileNames(referencedFile, host);
Debug.assert(!!declarationFilePath || isJavaScript(referencedFile.fileName), "Declaration file is not present only for javascript files");
declFileName = declarationFilePath || jsFilePath;
// Get the declaration file path
forEachExpectedEmitFile(host, getDeclFileName, referencedFile);
}
declFileName = getRelativePathToDirectoryOrUrl(
getDirectoryPath(normalizeSlashes(declarationFilePath)),
declFileName,
host.getCurrentDirectory(),
host.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ false);
if (declFileName) {
declFileName = getRelativePathToDirectoryOrUrl(
getDirectoryPath(normalizeSlashes(declarationFilePath)),
declFileName,
host.getCurrentDirectory(),
host.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ false);
referencePathsOutput += "/// <reference path=\"" + declFileName + "\" />" + newLine;
referencePathsOutput += "/// <reference path=\"" + declFileName + "\" />" + newLine;
}
return addedBundledEmitReference;
function getDeclFileName(emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) {
// Dont add reference path to this file if it is a bundled emit and caller asked not emit bundled file path
if (isBundledEmit && !addBundledFileReference) {
return;
}
Debug.assert(!!emitFileNames.declarationFilePath || isJavaScript(referencedFile.fileName), "Declaration file is not present only for javascript files");
declFileName = emitFileNames.declarationFilePath || emitFileNames.jsFilePath;
addedBundledEmitReference = isBundledEmit;
}
}
}
/* @internal */
export function writeDeclarationFile(declarationFilePath: string, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection) {
let emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFile);
export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection) {
let emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit);
let emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath);
if (!emitSkipped) {
let declarationOutput = emitDeclarationResult.referencePathsOutput

View File

@ -8131,7 +8131,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
if (declarationFilePath) {
emitSkipped = writeDeclarationFile(declarationFilePath, isBundledEmit ? undefined : sourceFiles[0], host, resolver, emitterDiagnostics) || emitSkipped;
emitSkipped = writeDeclarationFile(declarationFilePath, sourceFiles, isBundledEmit, host, resolver, emitterDiagnostics) || emitSkipped;
}
}
}

View File

@ -1792,48 +1792,6 @@ namespace ts {
declarationFilePath: string;
}
export function getEmitFileNames(sourceFile: SourceFile, host: EmitHost): EmitFileNames {
if (!isDeclarationFile(sourceFile)) {
let options = host.getCompilerOptions();
let jsFilePath: string;
if (shouldEmitToOwnFile(sourceFile, options)) {
let jsFilePath = getOwnEmitOutputFilePath(sourceFile, host,
sourceFile.languageVariant === LanguageVariant.JSX && options.jsx === JsxEmit.Preserve ? ".jsx" : ".js");
return {
jsFilePath,
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
declarationFilePath: !isJavaScript(sourceFile.fileName) ? getDeclarationEmitFilePath(jsFilePath, options) : undefined
};
}
else if (options.outFile || options.out) {
return getBundledEmitFileNames(options);
}
}
return {
jsFilePath: undefined,
sourceMapFilePath: undefined,
declarationFilePath: undefined
};
}
function getBundledEmitFileNames(options: CompilerOptions): EmitFileNames {
let jsFilePath = options.outFile || options.out;
return {
jsFilePath,
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
declarationFilePath: getDeclarationEmitFilePath(jsFilePath, options)
};
}
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
function getDeclarationEmitFilePath(jsFilePath: string, options: CompilerOptions) {
return options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined;
}
export function forEachExpectedEmitFile(host: EmitHost,
action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) => void,
targetSourceFile?: SourceFile) {
@ -1861,16 +1819,37 @@ namespace ts {
}
function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) {
action(getEmitFileNames(sourceFile, host), [sourceFile], /*isBundledEmit*/false);
let jsFilePath = getOwnEmitOutputFilePath(sourceFile, host,
sourceFile.languageVariant === LanguageVariant.JSX && options.jsx === JsxEmit.Preserve ? ".jsx" : ".js");
let emitFileNames: EmitFileNames = {
jsFilePath,
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
declarationFilePath: !isJavaScript(sourceFile.fileName) ? getDeclarationEmitFilePath(jsFilePath, options) : undefined
};
action(emitFileNames, [sourceFile], /*isBundledEmit*/false);
}
function onBundledEmit(host: EmitHost) {
let bundledSources = filter(host.getSourceFiles(),
sourceFile => !shouldEmitToOwnFile(sourceFile, host.getCompilerOptions()) && !isDeclarationFile(sourceFile));
let jsFilePath = options.outFile || options.out;
let emitFileNames: EmitFileNames = {
jsFilePath,
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
declarationFilePath: getDeclarationEmitFilePath(jsFilePath, options)
};
if (bundledSources.length) {
action(getBundledEmitFileNames(options), bundledSources, /*isBundledEmit*/true);
action(emitFileNames, bundledSources, /*isBundledEmit*/true);
}
}
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
return options.sourceMap ? jsFilePath + ".map" : undefined;
}
function getDeclarationEmitFilePath(jsFilePath: string, options: CompilerOptions) {
return options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined;
}
}
export function hasFile(sourceFiles: SourceFile[], fileName: string) {