Skip to content

Commit aa02ab5

Browse files
author
Yui
committed
Merge pull request #650 from Microsoft/getEmitOutput
GetEmitOutput And Testfiles
2 parents 07e3c7f + 9ee63fa commit aa02ab5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+860
-102
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7238,12 +7238,9 @@ module ts {
72387238
return target !== unknownSymbol && ((target.flags & SymbolFlags.Value) !== 0);
72397239
}
72407240

7241-
function shouldEmitDeclarations() {
7242-
// If the declaration emit and there are no errors being reported in program or by checker
7243-
// declarations can be emitted
7244-
return compilerOptions.declaration &&
7245-
!program.getDiagnostics().length &&
7246-
!getDiagnostics().length;
7241+
function hasSemanticErrors() {
7242+
// Return true if there is any semantic error in a file or globally
7243+
return getDiagnostics().length > 0 || getGlobalDiagnostics().length > 0;
72477244
}
72487245

72497246
function isReferencedImportDeclaration(node: ImportDeclaration): boolean {
@@ -7304,7 +7301,7 @@ module ts {
73047301
writeTypeToTextWriter(getReturnTypeOfSignature(signature), enclosingDeclaration, flags , writer);
73057302
}
73067303

7307-
function invokeEmitter() {
7304+
function invokeEmitter(targetSourceFile?: SourceFile) {
73087305
var resolver: EmitResolver = {
73097306
getProgram: () => program,
73107307
getLocalNameOfContainer: getLocalNameOfContainer,
@@ -7315,7 +7312,7 @@ module ts {
73157312
getNodeCheckFlags: getNodeCheckFlags,
73167313
getEnumMemberValue: getEnumMemberValue,
73177314
isTopLevelValueImportedViaEntityName: isTopLevelValueImportedViaEntityName,
7318-
shouldEmitDeclarations: shouldEmitDeclarations,
7315+
hasSemanticErrors: hasSemanticErrors,
73197316
isDeclarationVisible: isDeclarationVisible,
73207317
isImplementationOfOverload: isImplementationOfOverload,
73217318
writeTypeAtLocation: writeTypeAtLocation,
@@ -7325,7 +7322,7 @@ module ts {
73257322
isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile
73267323
};
73277324
checkProgram();
7328-
return emitFiles(resolver);
7325+
return emitFiles(resolver, targetSourceFile);
73297326
}
73307327

73317328
function initializeTypeChecker() {

src/compiler/core.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ module ts {
407407
return normalizedPathComponents(path, rootLength);
408408
}
409409

410-
export function getNormalizedPathFromPathCompoments(pathComponents: string[]) {
410+
export function getNormalizedPathFromPathComponents(pathComponents: string[]) {
411411
if (pathComponents && pathComponents.length) {
412412
return pathComponents[0] + pathComponents.slice(1).join(directorySeparator);
413413
}
@@ -468,7 +468,7 @@ module ts {
468468
var pathComponents = getNormalizedPathOrUrlComponents(relativeOrAbsolutePath, currentDirectory);
469469
var directoryComponents = getNormalizedPathOrUrlComponents(directoryPathOrUrl, currentDirectory);
470470
if (directoryComponents.length > 1 && directoryComponents[directoryComponents.length - 1] === "") {
471-
// If the directory path given was of type test/cases/ then we really need components of directry to be only till its name
471+
// If the directory path given was of type test/cases/ then we really need components of directory to be only till its name
472472
// that is ["test", "cases", ""] needs to be actually ["test", "cases"]
473473
directoryComponents.length--;
474474
}
@@ -494,7 +494,7 @@ module ts {
494494
}
495495

496496
// Cant find the relative path, get the absolute path
497-
var absolutePath = getNormalizedPathFromPathCompoments(pathComponents);
497+
var absolutePath = getNormalizedPathFromPathComponents(pathComponents);
498498
if (isAbsolutePathAnUrl && isRootedDiskPath(absolutePath)) {
499499
absolutePath = "file:///" + absolutePath;
500500
}

src/compiler/emitter.ts

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,22 @@ module ts {
2525
return indentStrings[1].length;
2626
}
2727

28-
export function emitFiles(resolver: EmitResolver): EmitResult {
28+
export function shouldEmitToOwnFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
29+
if (!(sourceFile.flags & NodeFlags.DeclarationFile)) {
30+
if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.filename, ".js")) {
31+
return true;
32+
}
33+
return false;
34+
}
35+
return false;
36+
}
37+
38+
export function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) {
39+
return isExternalModule(sourceFile) || (sourceFile.flags & NodeFlags.DeclarationFile) !== 0;
40+
}
41+
42+
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compilerOnSave feature
43+
export function emitFiles(resolver: EmitResolver, targetSourceFile?: SourceFile): EmitResult {
2944
var program = resolver.getProgram();
3045
var compilerHost = program.getCompilerHost();
3146
var compilerOptions = program.getCompilerOptions();
@@ -34,22 +49,14 @@ module ts {
3449
var newLine = program.getCompilerHost().getNewLine();
3550

3651
function getSourceFilePathInNewDir(newDirPath: string, sourceFile: SourceFile) {
37-
var sourceFilePath = getNormalizedPathFromPathCompoments(getNormalizedPathComponents(sourceFile.filename, compilerHost.getCurrentDirectory()));
52+
var sourceFilePath = getNormalizedPathFromPathComponents(getNormalizedPathComponents(sourceFile.filename, compilerHost.getCurrentDirectory()));
3853
sourceFilePath = sourceFilePath.replace(program.getCommonSourceDirectory(), "");
3954
return combinePaths(newDirPath, sourceFilePath);
4055
}
4156

42-
function shouldEmitToOwnFile(sourceFile: SourceFile) {
43-
if (!(sourceFile.flags & NodeFlags.DeclarationFile)) {
44-
if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.filename, ".js")) {
45-
return true;
46-
}
47-
}
48-
}
49-
5057
function getOwnEmitOutputFilePath(sourceFile: SourceFile, extension: string) {
51-
if (program.getCompilerOptions().outDir) {
52-
var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(getSourceFilePathInNewDir(program.getCompilerOptions().outDir, sourceFile));
58+
if (compilerOptions.outDir) {
59+
var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(getSourceFilePathInNewDir(compilerOptions.outDir, sourceFile));
5360
}
5461
else {
5562
var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(sourceFile.filename);
@@ -58,10 +65,6 @@ module ts {
5865
return emitOutputFilePathWithoutExtension + extension;
5966
}
6067

61-
function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) {
62-
return isExternalModule(sourceFile) || (sourceFile.flags & NodeFlags.DeclarationFile) !== 0;
63-
}
64-
6568
function getFirstConstructorWithBody(node: ClassDeclaration): ConstructorDeclaration {
6669
return forEach(node.members, member => {
6770
if (member.kind === SyntaxKind.Constructor && (<ConstructorDeclaration>member).body) {
@@ -3082,7 +3085,7 @@ module ts {
30823085
function writeReferencePath(referencedFile: SourceFile) {
30833086
var declFileName = referencedFile.flags & NodeFlags.DeclarationFile
30843087
? referencedFile.filename // Declaration file, use declaration file name
3085-
: shouldEmitToOwnFile(referencedFile)
3088+
: shouldEmitToOwnFile(referencedFile, compilerOptions)
30863089
? getOwnEmitOutputFilePath(referencedFile, ".d.ts") // Own output file so get the .d.ts file
30873090
: getModuleNameFromFilename(compilerOptions.out) + ".d.ts";// Global out file
30883091

@@ -3104,7 +3107,7 @@ module ts {
31043107

31053108
// All the references that are not going to be part of same file
31063109
if ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference
3107-
shouldEmitToOwnFile(referencedFile) || // This is referenced file is emitting its own js file
3110+
shouldEmitToOwnFile(referencedFile, compilerOptions) || // This is referenced file is emitting its own js file
31083111
!addedGlobalFileReference) { // Or the global out file corresponding to this reference was not added
31093112

31103113
writeReferencePath(referencedFile);
@@ -3161,29 +3164,54 @@ module ts {
31613164
}
31623165
}
31633166

3164-
var shouldEmitDeclarations = resolver.shouldEmitDeclarations();
3167+
var hasSemanticErrors = resolver.hasSemanticErrors();
3168+
31653169
function emitFile(jsFilePath: string, sourceFile?: SourceFile) {
31663170
emitJavaScript(jsFilePath, sourceFile);
3167-
if (shouldEmitDeclarations) {
3171+
if (!hasSemanticErrors && compilerOptions.declaration) {
31683172
emitDeclarations(jsFilePath, sourceFile);
31693173
}
31703174
}
31713175

3172-
forEach(program.getSourceFiles(), sourceFile => {
3173-
if (shouldEmitToOwnFile(sourceFile)) {
3174-
var jsFilePath = getOwnEmitOutputFilePath(sourceFile, ".js");
3175-
emitFile(jsFilePath, sourceFile);
3176-
}
3177-
});
3176+
if (targetSourceFile === undefined) {
3177+
forEach(program.getSourceFiles(), sourceFile => {
3178+
if (shouldEmitToOwnFile(sourceFile, compilerOptions)) {
3179+
var jsFilePath = getOwnEmitOutputFilePath(sourceFile, ".js");
3180+
emitFile(jsFilePath, sourceFile);
3181+
}
3182+
});
3183+
}
3184+
else {
3185+
// Emit only one file specified in targetFilename. This is mainly used in compilerOnSave feature
3186+
var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, ".js");
3187+
emitFile(jsFilePath, targetSourceFile);
3188+
}
3189+
31783190
if (compilerOptions.out) {
31793191
emitFile(compilerOptions.out);
31803192
}
3181-
3193+
31823194
// Sort and make the unique list of diagnostics
31833195
diagnostics.sort(compareDiagnostics);
31843196
diagnostics = deduplicateSortedDiagnostics(diagnostics);
31853197

3198+
// Update returnCode if there is any EmitterError
3199+
var hasEmitterError = forEach(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error);
3200+
3201+
// Check and update returnCode for syntactic and semantic
3202+
var returnCode: EmitReturnStatus;
3203+
if (hasEmitterError) {
3204+
returnCode = EmitReturnStatus.EmitErrorsEncountered;
3205+
} else if (hasSemanticErrors && compilerOptions.declaration) {
3206+
returnCode = EmitReturnStatus.DeclarationGenerationSkipped;
3207+
} else if (hasSemanticErrors && !compilerOptions.declaration) {
3208+
returnCode = EmitReturnStatus.JSGeneratedWithSemanticErrors;
3209+
} else {
3210+
returnCode = EmitReturnStatus.Succeeded;
3211+
}
3212+
31863213
return {
3214+
emitResultStatus: returnCode,
31873215
errors: diagnostics,
31883216
sourceMaps: sourceMapDataList
31893217
};

src/compiler/parser.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3965,11 +3965,11 @@ module ts {
39653965
// Each file contributes into common source file path
39663966
if (!(sourceFile.flags & NodeFlags.DeclarationFile)
39673967
&& !fileExtensionIs(sourceFile.filename, ".js")) {
3968-
var sourcePathCompoments = getNormalizedPathComponents(sourceFile.filename, host.getCurrentDirectory());
3969-
sourcePathCompoments.pop(); // FileName is not part of directory
3968+
var sourcePathComponents = getNormalizedPathComponents(sourceFile.filename, host.getCurrentDirectory());
3969+
sourcePathComponents.pop(); // FileName is not part of directory
39703970
if (commonPathComponents) {
3971-
for (var i = 0; i < Math.min(commonPathComponents.length, sourcePathCompoments.length); i++) {
3972-
if (commonPathComponents[i] !== sourcePathCompoments[i]) {
3971+
for (var i = 0; i < Math.min(commonPathComponents.length, sourcePathComponents.length); i++) {
3972+
if (commonPathComponents[i] !== sourcePathComponents[i]) {
39733973
if (i === 0) {
39743974
errors.push(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files));
39753975
return;
@@ -3982,18 +3982,18 @@ module ts {
39823982
}
39833983

39843984
// If the fileComponent path completely matched and less than already found update the length
3985-
if (sourcePathCompoments.length < commonPathComponents.length) {
3986-
commonPathComponents.length = sourcePathCompoments.length;
3985+
if (sourcePathComponents.length < commonPathComponents.length) {
3986+
commonPathComponents.length = sourcePathComponents.length;
39873987
}
39883988
}
39893989
else {
39903990
// first file
3991-
commonPathComponents = sourcePathCompoments;
3991+
commonPathComponents = sourcePathComponents;
39923992
}
39933993
}
39943994
});
39953995

3996-
commonSourceDirectory = getNormalizedPathFromPathCompoments(commonPathComponents);
3996+
commonSourceDirectory = getNormalizedPathFromPathComponents(commonPathComponents);
39973997
if (commonSourceDirectory) {
39983998
// Make sure directory path ends with directory separator so this string can directly
39993999
// used to replace with "" to get the relative path of the source file and the relative path doesn't

src/compiler/types.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ module ts {
577577
export interface SourceMapData {
578578
/** Where the sourcemap file is written */
579579
sourceMapFilePath: string;
580-
/** source map url written in the js file */
580+
/** source map URL written in the js file */
581581
jsSourceMappingURL: string;
582582
/** Source map's file field - js file name*/
583583
sourceMapFile: string;
@@ -596,7 +596,17 @@ module ts {
596596
sourceMapDecodedMappings: SourceMapSpan[];
597597
}
598598

599+
// Return code used by getEmitOutput function to indicate status of the function
600+
export enum EmitReturnStatus {
601+
Succeeded = 0, // All outputs generated as requested (.js, .map, .d.ts), no errors reported
602+
AllOutputGenerationSkipped = 1, // No .js generated because of syntax errors, or compiler options errors, nothing generated
603+
JSGeneratedWithSemanticErrors = 2, // .js and .map generated with semantic errors
604+
DeclarationGenerationSkipped = 3, // .d.ts generation skipped because of semantic errors or declaration emitter specific errors; Output .js with semantic errors
605+
EmitErrorsEncountered = 4 // Emitter errors occurred during emitting process
606+
}
607+
599608
export interface EmitResult {
609+
emitResultStatus: EmitReturnStatus;
600610
errors: Diagnostic[];
601611
sourceMaps: SourceMapData[]; // Array of sourceMapData if compiler emitted sourcemaps
602612
}
@@ -610,7 +620,7 @@ module ts {
610620
getSymbolCount(): number;
611621
getTypeCount(): number;
612622
checkProgram(): void;
613-
emitFiles(): EmitResult;
623+
emitFiles(targetSourceFile?: SourceFile): EmitResult;
614624
getParentOfSymbol(symbol: Symbol): Symbol;
615625
getTypeOfSymbol(symbol: Symbol): Type;
616626
getPropertiesOfType(type: Type): Symbol[];
@@ -668,7 +678,7 @@ module ts {
668678
isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean;
669679
getNodeCheckFlags(node: Node): NodeCheckFlags;
670680
getEnumMemberValue(node: EnumMember): number;
671-
shouldEmitDeclarations(): boolean;
681+
hasSemanticErrors(): boolean;
672682
isDeclarationVisible(node: Declaration): boolean;
673683
isImplementationOfOverload(node: FunctionDeclaration): boolean;
674684
writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void;

0 commit comments

Comments
 (0)