mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-17 01:49:57 -05:00
Merge pull request #5471 from Microsoft/jsFileCompilation
Compilation of Js Files
This commit is contained in:
@@ -31,13 +31,17 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] {
|
||||
const diagnostics: Diagnostic[] = [];
|
||||
const jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, host, ".js");
|
||||
emitDeclarations(host, resolver, diagnostics, jsFilePath, targetSourceFile);
|
||||
return diagnostics;
|
||||
const declarationDiagnostics = createDiagnosticCollection();
|
||||
forEachExpectedEmitFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
|
||||
return declarationDiagnostics.getDiagnostics(targetSourceFile.fileName);
|
||||
|
||||
function getDeclarationDiagnosticsFromFile({ declarationFilePath }, sources: SourceFile[], isBundledEmit: boolean) {
|
||||
emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit);
|
||||
}
|
||||
}
|
||||
|
||||
function emitDeclarations(host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit {
|
||||
function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string,
|
||||
sourceFiles: SourceFile[], isBundledEmit: boolean): DeclarationEmit {
|
||||
const newLine = host.getNewLine();
|
||||
const compilerOptions = host.getCompilerOptions();
|
||||
|
||||
@@ -58,7 +62,7 @@ namespace ts {
|
||||
let errorNameNode: DeclarationName;
|
||||
const emitJsDocComments = compilerOptions.removeComments ? function (declaration: Node) { } : writeJsDocComments;
|
||||
const emit = compilerOptions.stripInternal ? stripInternal : emitNode;
|
||||
let noDeclare = !root;
|
||||
let noDeclare: boolean;
|
||||
|
||||
let moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
|
||||
let asynchronousSubModuleDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[];
|
||||
@@ -68,105 +72,78 @@ 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
|
||||
// Emit references corresponding to each file
|
||||
const emittedReferencedFiles: SourceFile[] = [];
|
||||
let addedGlobalFileReference = false;
|
||||
let allSourcesModuleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
|
||||
forEach(sourceFiles, sourceFile => {
|
||||
// Dont emit for javascript file
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check what references need to be added
|
||||
if (!compilerOptions.noResolve) {
|
||||
let addedGlobalFileReference = false;
|
||||
forEach(root.referencedFiles, fileReference => {
|
||||
const referencedFile = tryResolveScriptReference(host, root, fileReference);
|
||||
forEach(sourceFile.referencedFiles, fileReference => {
|
||||
const 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)) {
|
||||
// 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;
|
||||
}
|
||||
emittedReferencedFiles.push(referencedFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
emitSourceFile(root);
|
||||
if (!isBundledEmit || !isExternalModule(sourceFile)) {
|
||||
noDeclare = false;
|
||||
emitSourceFile(sourceFile);
|
||||
}
|
||||
else if (isExternalModule(sourceFile)) {
|
||||
noDeclare = true;
|
||||
write(`declare module "${getResolvedExternalModuleName(host, sourceFile)}" {`);
|
||||
writeLine();
|
||||
increaseIndent();
|
||||
emitSourceFile(sourceFile);
|
||||
decreaseIndent();
|
||||
write("}");
|
||||
writeLine();
|
||||
}
|
||||
|
||||
// create asynchronous output for the importDeclarations
|
||||
if (moduleElementDeclarationEmitInfo.length) {
|
||||
const oldWriter = writer;
|
||||
forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
|
||||
if (aliasEmitInfo.isVisible) {
|
||||
if (aliasEmitInfo.isVisible && !aliasEmitInfo.asynchronousOutput) {
|
||||
Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration);
|
||||
createAndSetNewTextWriterWithSymbolWriter();
|
||||
Debug.assert(aliasEmitInfo.indent === 0);
|
||||
Debug.assert(aliasEmitInfo.indent === 0 || (aliasEmitInfo.indent === 1 && isBundledEmit));
|
||||
for (let i = 0; i < aliasEmitInfo.indent; i++) {
|
||||
increaseIndent();
|
||||
}
|
||||
writeImportDeclaration(<ImportDeclaration>aliasEmitInfo.node);
|
||||
aliasEmitInfo.asynchronousOutput = writer.getText();
|
||||
for (let i = 0; i < aliasEmitInfo.indent; i++) {
|
||||
decreaseIndent();
|
||||
}
|
||||
}
|
||||
});
|
||||
setWriter(oldWriter);
|
||||
|
||||
allSourcesModuleElementDeclarationEmitInfo = allSourcesModuleElementDeclarationEmitInfo.concat(moduleElementDeclarationEmitInfo);
|
||||
moduleElementDeclarationEmitInfo = [];
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Emit references corresponding to this file
|
||||
const emittedReferencedFiles: SourceFile[] = [];
|
||||
let prevModuleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
|
||||
forEach(host.getSourceFiles(), sourceFile => {
|
||||
if (!isDeclarationFile(sourceFile)) {
|
||||
// Check what references need to be added
|
||||
if (!compilerOptions.noResolve) {
|
||||
forEach(sourceFile.referencedFiles, fileReference => {
|
||||
const referencedFile = tryResolveScriptReference(host, sourceFile, fileReference);
|
||||
|
||||
// If the reference file is a declaration file, emit that reference
|
||||
if (referencedFile && (isDeclarationFile(referencedFile) &&
|
||||
!contains(emittedReferencedFiles, referencedFile))) { // If the file reference was not already emitted
|
||||
|
||||
writeReferencePath(referencedFile);
|
||||
emittedReferencedFiles.push(referencedFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
|
||||
noDeclare = false;
|
||||
emitSourceFile(sourceFile);
|
||||
}
|
||||
else if (isExternalModule(sourceFile)) {
|
||||
noDeclare = true;
|
||||
write(`declare module "${getResolvedExternalModuleName(host, sourceFile)}" {`);
|
||||
writeLine();
|
||||
increaseIndent();
|
||||
emitSourceFile(sourceFile);
|
||||
decreaseIndent();
|
||||
write("}");
|
||||
writeLine();
|
||||
|
||||
// create asynchronous output for the importDeclarations
|
||||
if (moduleElementDeclarationEmitInfo.length) {
|
||||
const oldWriter = writer;
|
||||
forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
|
||||
if (aliasEmitInfo.isVisible && !aliasEmitInfo.asynchronousOutput) {
|
||||
Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration);
|
||||
createAndSetNewTextWriterWithSymbolWriter();
|
||||
Debug.assert(aliasEmitInfo.indent === 1);
|
||||
increaseIndent();
|
||||
writeImportDeclaration(<ImportDeclaration>aliasEmitInfo.node);
|
||||
aliasEmitInfo.asynchronousOutput = writer.getText();
|
||||
decreaseIndent();
|
||||
}
|
||||
});
|
||||
setWriter(oldWriter);
|
||||
}
|
||||
prevModuleElementDeclarationEmitInfo = prevModuleElementDeclarationEmitInfo.concat(moduleElementDeclarationEmitInfo);
|
||||
moduleElementDeclarationEmitInfo = [];
|
||||
}
|
||||
});
|
||||
moduleElementDeclarationEmitInfo = moduleElementDeclarationEmitInfo.concat(prevModuleElementDeclarationEmitInfo);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
reportedDeclarationError,
|
||||
moduleElementDeclarationEmitInfo,
|
||||
moduleElementDeclarationEmitInfo: allSourcesModuleElementDeclarationEmitInfo,
|
||||
synchronousDeclarationOutput: writer.getText(),
|
||||
referencePathsOutput,
|
||||
};
|
||||
@@ -278,14 +255,14 @@ namespace ts {
|
||||
const errorInfo = writer.getSymbolAccessibilityDiagnostic(symbolAccesibilityResult);
|
||||
if (errorInfo) {
|
||||
if (errorInfo.typeName) {
|
||||
diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
|
||||
emitterDiagnostics.add(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
|
||||
errorInfo.diagnosticMessage,
|
||||
getTextOfNodeFromSourceText(currentText, errorInfo.typeName),
|
||||
symbolAccesibilityResult.errorSymbolName,
|
||||
symbolAccesibilityResult.errorModuleName));
|
||||
}
|
||||
else {
|
||||
diagnostics.push(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
|
||||
emitterDiagnostics.add(createDiagnosticForNode(symbolAccesibilityResult.errorNode || errorInfo.errorNode,
|
||||
errorInfo.diagnosticMessage,
|
||||
symbolAccesibilityResult.errorSymbolName,
|
||||
symbolAccesibilityResult.errorModuleName));
|
||||
@@ -300,7 +277,8 @@ namespace ts {
|
||||
|
||||
function reportInaccessibleThisError() {
|
||||
if (errorNameNode) {
|
||||
diagnostics.push(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_this_type_A_type_annotation_is_necessary,
|
||||
reportedDeclarationError = true;
|
||||
emitterDiagnostics.add(createDiagnosticForNode(errorNameNode, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_this_type_A_type_annotation_is_necessary,
|
||||
declarationNameToString(errorNameNode)));
|
||||
}
|
||||
}
|
||||
@@ -743,7 +721,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitExternalModuleSpecifier(moduleSpecifier: Expression) {
|
||||
if (moduleSpecifier.kind === SyntaxKind.StringLiteral && (!root) && (compilerOptions.out || compilerOptions.outFile)) {
|
||||
if (moduleSpecifier.kind === SyntaxKind.StringLiteral && isBundledEmit) {
|
||||
const moduleName = getExternalModuleNameFromDeclaration(host, resolver, moduleSpecifier.parent as (ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration));
|
||||
if (moduleName) {
|
||||
write("\"");
|
||||
@@ -1643,34 +1621,58 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function writeReferencePath(referencedFile: SourceFile) {
|
||||
let declFileName = referencedFile.flags & NodeFlags.DeclarationFile
|
||||
? referencedFile.fileName // Declaration file, use declaration file name
|
||||
: shouldEmitToOwnFile(referencedFile, compilerOptions)
|
||||
? getOwnEmitOutputFilePath(referencedFile, host, ".d.ts") // Own output file so get the .d.ts file
|
||||
: removeFileExtension(compilerOptions.outFile || compilerOptions.out) + ".d.ts"; // Global out file
|
||||
/**
|
||||
* 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;
|
||||
let addedBundledEmitReference = false;
|
||||
if (isDeclarationFile(referencedFile)) {
|
||||
// Declaration file, use declaration file name
|
||||
declFileName = referencedFile.fileName;
|
||||
}
|
||||
else {
|
||||
// Get the declaration file path
|
||||
forEachExpectedEmitFile(host, getDeclFileName, referencedFile);
|
||||
}
|
||||
|
||||
declFileName = getRelativePathToDirectoryOrUrl(
|
||||
getDirectoryPath(normalizeSlashes(jsFilePath)),
|
||||
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 || isSourceFileJavaScript(referencedFile), "Declaration file is not present only for javascript files");
|
||||
declFileName = emitFileNames.declarationFilePath || emitFileNames.jsFilePath;
|
||||
addedBundledEmitReference = isBundledEmit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function writeDeclarationFile(jsFilePath: string, sourceFile: SourceFile, host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[]) {
|
||||
const emitDeclarationResult = emitDeclarations(host, resolver, diagnostics, jsFilePath, sourceFile);
|
||||
// TODO(shkamat): Should we not write any declaration file if any of them can produce error,
|
||||
// or should we just not write this file like we are doing now
|
||||
if (!emitDeclarationResult.reportedDeclarationError) {
|
||||
export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection) {
|
||||
const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit);
|
||||
const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath);
|
||||
if (!emitSkipped) {
|
||||
const declarationOutput = emitDeclarationResult.referencePathsOutput
|
||||
+ getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
|
||||
writeFile(host, diagnostics, removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, host.getCompilerOptions().emitBOM);
|
||||
writeFile(host, emitterDiagnostics, declarationFilePath, declarationOutput, host.getCompilerOptions().emitBOM);
|
||||
}
|
||||
return emitSkipped;
|
||||
|
||||
function getDeclarationOutput(synchronousDeclarationOutput: string, moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[]) {
|
||||
let appliedSyncOutputPos = 0;
|
||||
|
||||
Reference in New Issue
Block a user