2014-12-16 22:14:14 +01:00
/// <reference path="checker.ts"/>
2014-07-13 01:04:16 +02:00
module ts {
2014-10-13 21:35:17 +02:00
interface EmitTextWriter {
2014-09-29 18:45:39 +02:00
write ( s : string ) : void ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( sourceFile : SourceFile , node : Node ) : void ;
2014-10-13 21:35:17 +02:00
writeLine ( ) : void ;
increaseIndent ( ) : void ;
decreaseIndent ( ) : void ;
2014-09-29 18:45:39 +02:00
getText ( ) : string ;
2014-08-16 01:58:38 +02:00
rawWrite ( s : string ) : void ;
2014-07-17 00:39:14 +02:00
writeLiteral ( s : string ) : void ;
getTextPos ( ) : number ;
getLine ( ) : number ;
getColumn ( ) : number ;
2014-08-05 02:59:33 +02:00
getIndent ( ) : number ;
2014-07-13 01:04:16 +02:00
}
2015-02-08 17:03:15 +01:00
interface ExternalImportInfo {
2015-02-08 21:13:56 +01:00
importNode : ImportDeclaration | ImportEqualsDeclaration ;
declarationNode? : ImportEqualsDeclaration | ImportClause | NamespaceImport ;
namedImports? : NamedImports ;
tempName? : Identifier ; // Temporary name for module instance
2015-02-08 17:03:15 +01:00
}
2014-11-11 00:36:10 +01:00
interface SymbolAccessibilityDiagnostic {
errorNode : Node ;
diagnosticMessage : DiagnosticMessage ;
typeName? : DeclarationName ;
}
type GetSymbolAccessibilityDiagnostic = ( symbolAccesibilityResult : SymbolAccessiblityResult ) = > SymbolAccessibilityDiagnostic ;
2014-11-21 05:24:08 +01:00
interface EmitTextWriterWithSymbolWriter extends EmitTextWriter , SymbolWriter {
2014-11-11 00:36:10 +01:00
getSymbolAccessibilityDiagnostic : GetSymbolAccessibilityDiagnostic ;
2014-10-13 21:35:17 +02:00
}
2014-11-21 05:24:08 +01:00
interface AliasDeclarationEmitInfo {
2015-02-11 02:02:11 +01:00
declaration : AnyImportSyntax ;
2014-10-14 21:16:26 +02:00
outputPos : number ;
indent : number ;
asynchronousOutput? : string ; // If the output for alias was written asynchronously, the corresponding output
2015-02-11 02:02:11 +01:00
isVisible? : boolean ;
2014-10-14 21:16:26 +02:00
}
2014-11-21 05:24:08 +01:00
interface DeclarationEmit {
reportedDeclarationError : boolean ;
aliasDeclarationEmitInfo : AliasDeclarationEmitInfo [ ] ;
synchronousDeclarationOutput : string ;
referencePathsOutput : string ;
2014-10-13 21:35:17 +02:00
}
2014-08-14 23:43:28 +02:00
var indentStrings : string [ ] = [ "" , " " ] ;
2014-09-29 18:45:39 +02:00
export function getIndentString ( level : number ) {
2014-08-14 23:43:28 +02:00
if ( indentStrings [ level ] === undefined ) {
indentStrings [ level ] = getIndentString ( level - 1 ) + indentStrings [ 1 ] ;
}
return indentStrings [ level ] ;
}
function getIndentSize() {
return indentStrings [ 1 ] . length ;
2014-07-13 01:04:16 +02:00
}
2014-09-12 21:57:00 +02:00
export function shouldEmitToOwnFile ( sourceFile : SourceFile , compilerOptions : CompilerOptions ) : boolean {
2014-10-09 03:15:07 +02:00
if ( ! isDeclarationFile ( sourceFile ) ) {
2015-02-04 01:08:46 +01:00
if ( ( isExternalModule ( sourceFile ) || ! compilerOptions . out ) && ! fileExtensionIs ( sourceFile . fileName , ".js" ) ) {
2014-09-05 00:10:37 +02:00
return true ;
}
2014-09-12 21:57:00 +02:00
return false ;
2014-09-05 00:10:37 +02:00
}
2014-09-12 21:57:00 +02:00
return false ;
}
2014-09-17 02:29:45 +02:00
2014-09-12 21:57:00 +02:00
export function isExternalModuleOrDeclarationFile ( sourceFile : SourceFile ) {
2014-10-09 23:19:36 +02:00
return isExternalModule ( sourceFile ) || isDeclarationFile ( sourceFile ) ;
2014-09-05 00:10:37 +02:00
}
2014-11-21 05:24:08 +01:00
function createTextWriter ( newLine : String ) : EmitTextWriter {
2014-10-11 01:44:14 +02:00
var output = "" ;
var indent = 0 ;
var lineStart = true ;
var lineCount = 0 ;
var linePos = 0 ;
2014-07-16 19:49:11 +02:00
2014-10-11 01:44:14 +02:00
function write ( s : string ) {
if ( s && s . length ) {
if ( lineStart ) {
output += getIndentString ( indent ) ;
lineStart = false ;
}
output += s ;
}
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
function rawWrite ( s : string ) {
if ( s !== undefined ) {
if ( lineStart ) {
lineStart = false ;
}
output += s ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
}
function writeLiteral ( s : string ) {
if ( s && s . length ) {
write ( s ) ;
2014-11-21 05:24:08 +01:00
var lineStartsOfS = computeLineStarts ( s ) ;
2014-10-11 01:44:14 +02:00
if ( lineStartsOfS . length > 1 ) {
lineCount = lineCount + lineStartsOfS . length - 1 ;
linePos = output . length - s . length + lineStartsOfS [ lineStartsOfS . length - 1 ] ;
}
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
function writeLine() {
if ( ! lineStart ) {
output += newLine ;
lineCount ++ ;
linePos = output . length ;
lineStart = true ;
}
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
function writeTextOfNode ( sourceFile : SourceFile , node : Node ) {
write ( getSourceTextOfNodeFromSourceFile ( sourceFile , node ) ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
return {
2014-11-21 05:24:08 +01:00
write ,
rawWrite ,
writeTextOfNode ,
writeLiteral ,
writeLine ,
2014-10-11 01:44:14 +02:00
increaseIndent : ( ) = > indent ++ ,
decreaseIndent : ( ) = > indent -- ,
getIndent : ( ) = > indent ,
getTextPos : ( ) = > output . length ,
getLine : ( ) = > lineCount + 1 ,
getColumn : ( ) = > lineStart ? indent * getIndentSize ( ) + 1 : output.length - linePos + 1 ,
getText : ( ) = > output ,
} ;
}
2014-07-17 00:39:14 +02:00
2014-10-13 19:53:57 +02:00
function getLineOfLocalPosition ( currentSourceFile : SourceFile , pos : number ) {
2015-01-16 21:02:12 +01:00
return getLineAndCharacterOfPosition ( currentSourceFile , pos ) . line ;
2014-10-11 01:44:14 +02:00
}
2014-07-16 19:49:11 +02:00
2014-10-13 19:53:57 +02:00
function emitNewLineBeforeLeadingComments ( currentSourceFile : SourceFile , writer : EmitTextWriter , node : TextRange , leadingComments : CommentRange [ ] ) {
2014-10-11 01:44:14 +02:00
// If the leading comments start on different line than the start of node, write new line
if ( leadingComments && leadingComments . length && node . pos !== leadingComments [ 0 ] . pos &&
2014-10-13 19:53:57 +02:00
getLineOfLocalPosition ( currentSourceFile , node . pos ) !== getLineOfLocalPosition ( currentSourceFile , leadingComments [ 0 ] . pos ) ) {
2014-10-11 01:44:14 +02:00
writer . writeLine ( ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-17 00:39:14 +02:00
2014-10-13 19:53:57 +02:00
function emitComments ( currentSourceFile : SourceFile , writer : EmitTextWriter , comments : CommentRange [ ] , trailingSeparator : boolean , newLine : string ,
writeComment : ( currentSourceFile : SourceFile , writer : EmitTextWriter , comment : CommentRange , newLine : string ) = > void ) {
2014-10-11 01:44:14 +02:00
var emitLeadingSpace = ! trailingSeparator ;
forEach ( comments , comment = > {
if ( emitLeadingSpace ) {
writer . write ( " " ) ;
emitLeadingSpace = false ;
}
2014-10-13 19:53:57 +02:00
writeComment ( currentSourceFile , writer , comment , newLine ) ;
2014-10-11 01:44:14 +02:00
if ( comment . hasTrailingNewLine ) {
writer . writeLine ( ) ;
}
else if ( trailingSeparator ) {
writer . write ( " " ) ;
2014-07-17 00:39:14 +02:00
}
else {
2014-10-11 01:44:14 +02:00
// Emit leading space to separate comment during next comment emit
emitLeadingSpace = true ;
}
} ) ;
}
2014-07-17 00:39:14 +02:00
2014-10-13 19:53:57 +02:00
function writeCommentRange ( currentSourceFile : SourceFile , writer : EmitTextWriter , comment : CommentRange , newLine : string ) {
2014-10-11 01:44:14 +02:00
if ( currentSourceFile . text . charCodeAt ( comment . pos + 1 ) === CharacterCodes . asterisk ) {
2015-01-16 21:02:12 +01:00
var firstCommentLineAndCharacter = getLineAndCharacterOfPosition ( currentSourceFile , comment . pos ) ;
2015-01-22 20:23:27 +01:00
var lastLine = getLineStarts ( currentSourceFile ) . length ;
2014-10-11 01:44:14 +02:00
var firstCommentLineIndent : number ;
for ( var pos = comment . pos , currentLine = firstCommentLineAndCharacter . line ; pos < comment . end ; currentLine ++ ) {
2015-01-22 20:23:27 +01:00
var nextLineStart = currentLine === lastLine ? ( comment . end + 1 ) : getPositionFromLineAndCharacter ( currentSourceFile , currentLine + 1 , /*character*/ 1 ) ;
2014-10-11 01:44:14 +02:00
if ( pos !== comment . pos ) {
// If we are not emitting first line, we need to write the spaces to adjust the alignment
if ( firstCommentLineIndent === undefined ) {
2015-01-16 21:02:12 +01:00
firstCommentLineIndent = calculateIndent ( getPositionFromLineAndCharacter ( currentSourceFile , firstCommentLineAndCharacter . line , /*character*/ 1 ) ,
2014-10-11 01:44:14 +02:00
comment . pos ) ;
}
// These are number of spaces writer is going to write at current indent
var currentWriterIndentSpacing = writer . getIndent ( ) * getIndentSize ( ) ;
// Number of spaces we want to be writing
// eg: Assume writer indent
// module m {
// /* starts at character 9 this is line 1
// * starts at character pos 4 line --1 = 8 - 8 + 3
// More left indented comment */ --2 = 8 - 8 + 2
// class c { }
// }
// module m {
// /* this is line 1 -- Assume current writer indent 8
// * line --3 = 8 - 4 + 5
// More right indented comment */ --4 = 8 - 4 + 11
// class c { }
// }
var spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + calculateIndent ( pos , nextLineStart ) ;
if ( spacesToEmit > 0 ) {
var numberOfSingleSpacesToEmit = spacesToEmit % getIndentSize ( ) ;
var indentSizeSpaceString = getIndentString ( ( spacesToEmit - numberOfSingleSpacesToEmit ) / getIndentSize ( ) ) ;
// Write indent size string ( in eg 1: = "", 2: "" , 3: string with 8 spaces 4: string with 12 spaces
writer . rawWrite ( indentSizeSpaceString ) ;
// Emit the single spaces (in eg: 1: 3 spaces, 2: 2 spaces, 3: 1 space, 4: 3 spaces)
while ( numberOfSingleSpacesToEmit ) {
writer . rawWrite ( " " ) ;
numberOfSingleSpacesToEmit -- ;
}
}
else {
// No spaces to emit write empty string
writer . rawWrite ( "" ) ;
2014-07-17 00:39:14 +02:00
}
}
2014-10-11 01:44:14 +02:00
// Write the comment line text
writeTrimmedCurrentLine ( pos , nextLineStart ) ;
pos = nextLineStart ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
}
else {
// Single line comment of style //....
writer . write ( currentSourceFile . text . substring ( comment . pos , comment . end ) ) ;
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
function writeTrimmedCurrentLine ( pos : number , nextLineStart : number ) {
var end = Math . min ( comment . end , nextLineStart - 1 ) ;
var currentLineText = currentSourceFile . text . substring ( pos , end ) . replace ( /^\s+|\s+$/g , '' ) ;
if ( currentLineText ) {
// trimmed forward and ending spaces text
writer . write ( currentLineText ) ;
if ( end !== comment . end ) {
writer . writeLine ( ) ;
2014-08-16 01:58:38 +02:00
}
}
2014-10-11 01:44:14 +02:00
else {
// Empty string - make sure we write empty line
writer . writeLiteral ( newLine ) ;
}
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function calculateIndent ( pos : number , end : number ) {
var currentLineIndent = 0 ;
for ( ; pos < end && isWhiteSpace ( currentSourceFile . text . charCodeAt ( pos ) ) ; pos ++ ) {
if ( currentSourceFile . text . charCodeAt ( pos ) === CharacterCodes . tab ) {
// Tabs = TabSize = indent size and go to next tabStop
currentLineIndent += getIndentSize ( ) - ( currentLineIndent % getIndentSize ( ) ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else {
// Single space
currentLineIndent ++ ;
2014-07-13 01:04:16 +02:00
}
}
2014-10-11 01:44:14 +02:00
return currentLineIndent ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
}
function getFirstConstructorWithBody ( node : ClassDeclaration ) : ConstructorDeclaration {
return forEach ( node . members , member = > {
2014-12-16 12:19:13 +01:00
if ( member . kind === SyntaxKind . Constructor && nodeIsPresent ( ( < ConstructorDeclaration > member ) . body ) ) {
2014-10-11 01:44:14 +02:00
return < ConstructorDeclaration > member ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
} ) ;
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
function getAllAccessorDeclarations ( node : ClassDeclaration , accessor : AccessorDeclaration ) {
var firstAccessor : AccessorDeclaration ;
var getAccessor : AccessorDeclaration ;
var setAccessor : AccessorDeclaration ;
2014-11-18 00:53:03 +01:00
if ( accessor . name . kind === SyntaxKind . ComputedPropertyName ) {
firstAccessor = accessor ;
if ( accessor . kind === SyntaxKind . GetAccessor ) {
getAccessor = accessor ;
}
else if ( accessor . kind === SyntaxKind . SetAccessor ) {
setAccessor = accessor ;
}
else {
Debug . fail ( "Accessor has wrong kind" ) ;
}
}
else {
forEach ( node . members , ( member : Declaration ) = > {
2014-07-17 00:39:14 +02:00
if ( ( member . kind === SyntaxKind . GetAccessor || member . kind === SyntaxKind . SetAccessor ) &&
2014-11-05 21:50:30 +01:00
( < Identifier > member . name ) . text === ( < Identifier > accessor . name ) . text &&
2014-07-17 00:39:14 +02:00
( member . flags & NodeFlags . Static ) === ( accessor . flags & NodeFlags . Static ) ) {
if ( ! firstAccessor ) {
firstAccessor = < AccessorDeclaration > member ;
}
if ( member . kind === SyntaxKind . GetAccessor && ! getAccessor ) {
getAccessor = < AccessorDeclaration > member ;
}
2014-07-13 01:04:16 +02:00
2014-07-17 00:39:14 +02:00
if ( member . kind === SyntaxKind . SetAccessor && ! setAccessor ) {
setAccessor = < AccessorDeclaration > member ;
}
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
} ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
return {
2014-11-21 05:24:08 +01:00
firstAccessor ,
getAccessor ,
setAccessor
2014-10-11 01:44:14 +02:00
} ;
}
2014-07-13 01:04:16 +02:00
2014-12-16 22:52:47 +01:00
function getSourceFilePathInNewDir ( sourceFile : SourceFile , host : EmitHost , newDirPath : string ) {
2015-02-04 01:08:46 +01:00
var sourceFilePath = getNormalizedAbsolutePath ( sourceFile . fileName , host . getCurrentDirectory ( ) ) ;
2014-12-16 22:52:47 +01:00
sourceFilePath = sourceFilePath . replace ( host . getCommonSourceDirectory ( ) , "" ) ;
2014-10-11 01:44:14 +02:00
return combinePaths ( newDirPath , sourceFilePath ) ;
}
2014-07-17 00:39:14 +02:00
2014-12-16 22:52:47 +01:00
function getOwnEmitOutputFilePath ( sourceFile : SourceFile , host : EmitHost , extension : string ) {
var compilerOptions = host . getCompilerOptions ( ) ;
2014-10-11 01:44:14 +02:00
if ( compilerOptions . outDir ) {
2014-12-16 22:52:47 +01:00
var emitOutputFilePathWithoutExtension = removeFileExtension ( getSourceFilePathInNewDir ( sourceFile , host , compilerOptions . outDir ) ) ;
2014-10-11 01:44:14 +02:00
}
else {
2015-02-04 01:08:46 +01:00
var emitOutputFilePathWithoutExtension = removeFileExtension ( sourceFile . fileName ) ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
return emitOutputFilePathWithoutExtension + extension ;
}
2014-08-16 01:58:38 +02:00
2015-02-04 01:08:46 +01:00
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 ) ) ;
2014-10-11 01:44:14 +02:00
} ) ;
}
2014-07-13 01:04:16 +02:00
2014-12-16 22:52:47 +01:00
function emitDeclarations ( host : EmitHost , resolver : EmitResolver , diagnostics : Diagnostic [ ] , jsFilePath : string , root? : SourceFile ) : DeclarationEmit {
2014-12-16 23:42:58 +01:00
var newLine = host . getNewLine ( ) ;
2014-12-16 22:52:47 +01:00
var compilerOptions = host . getCompilerOptions ( ) ;
2015-01-16 16:15:31 +01:00
var languageVersion = compilerOptions . target || ScriptTarget . ES3 ;
2014-07-17 00:39:14 +02:00
2014-11-21 05:24:08 +01:00
var write : ( s : string ) = > void ;
var writeLine : ( ) = > void ;
var increaseIndent : ( ) = > void ;
var decreaseIndent : ( ) = > void ;
var writeTextOfNode : ( sourceFile : SourceFile , node : Node ) = > void ;
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
var writer = createAndSetNewTextWriterWithSymbolWriter ( ) ;
2014-10-11 01:44:14 +02:00
var enclosingDeclaration : Node ;
2014-07-17 00:39:14 +02:00
var currentSourceFile : SourceFile ;
2014-10-11 01:44:14 +02:00
var reportedDeclarationError = false ;
2014-11-30 23:21:34 +01:00
var emitJsDocComments = compilerOptions . removeComments ? function ( declaration : Node ) { } : writeJsDocComments ;
2015-02-03 22:15:28 +01:00
var emit = compilerOptions . stripInternal ? stripInternal : emitNode ;
2014-10-11 01:44:14 +02:00
2014-11-21 05:24:08 +01:00
var aliasDeclarationEmitInfo : AliasDeclarationEmitInfo [ ] = [ ] ;
2015-02-03 21:46:01 +01:00
// Contains the reference paths that needs to go in the declaration file.
// Collecting this separately because reference paths need to be first thing in the declaration file
// and we could be collecting these paths from multiple files into single one with --out option
var referencePathsOutput = "" ;
if ( root ) {
// Emitting just a single file, so emit references in this file only
if ( ! compilerOptions . noResolve ) {
var addedGlobalFileReference = false ;
forEach ( root . referencedFiles , fileReference = > {
var referencedFile = tryResolveScriptReference ( host , root , 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 ;
}
}
} ) ;
}
2015-02-03 22:15:28 +01:00
emitSourceFile ( root ) ;
2015-02-11 02:02:11 +01:00
// create asynchronous output for the importDeclarations
if ( aliasDeclarationEmitInfo . length ) {
var oldWriter = writer ;
forEach ( aliasDeclarationEmitInfo , aliasEmitInfo = > {
if ( aliasEmitInfo . isVisible ) {
Debug . assert ( aliasEmitInfo . declaration . kind === SyntaxKind . ImportDeclaration ) ;
createAndSetNewTextWriterWithSymbolWriter ( ) ;
Debug . assert ( aliasEmitInfo . indent === 0 ) ;
writeImportDeclaration ( < ImportDeclaration > aliasEmitInfo . declaration ) ;
aliasEmitInfo . asynchronousOutput = writer . getText ( ) ;
}
} ) ;
setWriter ( oldWriter ) ;
}
2015-02-03 21:46:01 +01:00
}
else {
// Emit references corresponding to this file
var emittedReferencedFiles : SourceFile [ ] = [ ] ;
forEach ( host . getSourceFiles ( ) , sourceFile = > {
if ( ! isExternalModuleOrDeclarationFile ( sourceFile ) ) {
// Check what references need to be added
if ( ! compilerOptions . noResolve ) {
forEach ( sourceFile . referencedFiles , fileReference = > {
var 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 ) ;
}
} ) ;
}
2015-02-03 22:15:28 +01:00
emitSourceFile ( sourceFile ) ;
2015-02-03 21:46:01 +01:00
}
} ) ;
}
return {
reportedDeclarationError ,
aliasDeclarationEmitInfo ,
synchronousDeclarationOutput : writer.getText ( ) ,
referencePathsOutput ,
}
2015-02-03 22:15:28 +01:00
function hasInternalAnnotation ( range : CommentRange ) {
var text = currentSourceFile . text ;
var comment = text . substring ( range . pos , range . end ) ;
return comment . indexOf ( "@internal" ) >= 0 ;
}
function stripInternal ( node : Node ) {
if ( node ) {
var leadingCommentRanges = getLeadingCommentRanges ( currentSourceFile . text , node . pos ) ;
if ( forEach ( leadingCommentRanges , hasInternalAnnotation ) ) {
return ;
}
emitNode ( node ) ;
}
}
2014-11-21 05:24:08 +01:00
function createAndSetNewTextWriterWithSymbolWriter ( ) : EmitTextWriterWithSymbolWriter {
var writer = < EmitTextWriterWithSymbolWriter > createTextWriter ( newLine ) ;
writer . trackSymbol = trackSymbol ;
writer . writeKeyword = writer . write ;
writer . writeOperator = writer . write ;
writer . writePunctuation = writer . write ;
writer . writeSpace = writer . write ;
writer . writeStringLiteral = writer . writeLiteral ;
writer . writeParameter = writer . write ;
writer . writeSymbol = writer . write ;
setWriter ( writer ) ;
return writer ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function setWriter ( newWriter : EmitTextWriterWithSymbolWriter ) {
writer = newWriter ;
write = newWriter . write ;
writeTextOfNode = newWriter . writeTextOfNode ;
writeLine = newWriter . writeLine ;
increaseIndent = newWriter . increaseIndent ;
decreaseIndent = newWriter . decreaseIndent ;
2014-08-21 01:50:28 +02:00
}
2015-02-11 02:02:11 +01:00
function writeAsychronousImportEqualsDeclarations ( anyImportSyntax : AnyImportSyntax [ ] ) {
2014-10-11 01:44:14 +02:00
var oldWriter = writer ;
2015-02-11 02:02:11 +01:00
forEach ( anyImportSyntax , aliasToWrite = > {
2014-10-11 01:44:14 +02:00
var aliasEmitInfo = forEach ( aliasDeclarationEmitInfo , declEmitInfo = > declEmitInfo . declaration === aliasToWrite ? declEmitInfo : undefined ) ;
2014-10-22 19:23:15 +02:00
// If the alias was marked as not visible when we saw its declaration, we would have saved the aliasEmitInfo, but if we haven't yet visited the alias declaration
// then we don't need to write it at this point. We will write it when we actually see its declaration
// Eg.
// export function bar(a: foo.Foo) { }
// import foo = require("foo");
// Writing of function bar would mark alias declaration foo as visible but we haven't yet visited that declaration so do nothing,
// we would write alias foo declaration when we visit it since it would now be marked as visible
if ( aliasEmitInfo ) {
2015-02-11 02:02:11 +01:00
if ( aliasToWrite . kind === SyntaxKind . ImportEqualsDeclaration ) {
createAndSetNewTextWriterWithSymbolWriter ( ) ;
for ( var declarationIndent = aliasEmitInfo . indent ; declarationIndent ; declarationIndent -- ) {
increaseIndent ( ) ;
}
writeImportEqualsDeclaration ( < ImportEqualsDeclaration > aliasToWrite ) ;
aliasEmitInfo . asynchronousOutput = writer . getText ( ) ;
}
else {
// we have to create asynchronous output only after we have collected complete information
// because it is possible to enable multiple bindings as asynchronously visible
aliasEmitInfo . isVisible = true ;
2014-10-22 19:23:15 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-17 00:39:14 +02:00
} ) ;
2014-11-21 05:24:08 +01:00
setWriter ( oldWriter ) ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function handleSymbolAccessibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) {
2014-10-11 01:44:14 +02:00
if ( symbolAccesibilityResult . accessibility === SymbolAccessibility . Accessible ) {
// write the aliases
if ( symbolAccesibilityResult && symbolAccesibilityResult . aliasesToMakeVisible ) {
2015-01-27 23:42:20 +01:00
writeAsychronousImportEqualsDeclarations ( symbolAccesibilityResult . aliasesToMakeVisible ) ;
2014-08-15 23:32:08 +02:00
}
2014-10-11 01:44:14 +02:00
}
else {
// Report error
reportedDeclarationError = true ;
2014-11-21 05:24:08 +01:00
var errorInfo = writer . getSymbolAccessibilityDiagnostic ( symbolAccesibilityResult ) ;
2014-10-11 01:44:14 +02:00
if ( errorInfo ) {
if ( errorInfo . typeName ) {
2014-11-21 05:24:08 +01:00
diagnostics . push ( createDiagnosticForNode ( symbolAccesibilityResult . errorNode || errorInfo . errorNode ,
2014-10-11 01:44:14 +02:00
errorInfo . diagnosticMessage ,
2014-11-21 05:24:08 +01:00
getSourceTextOfNodeFromSourceFile ( currentSourceFile , errorInfo . typeName ) ,
2014-10-11 01:44:14 +02:00
symbolAccesibilityResult . errorSymbolName ,
symbolAccesibilityResult . errorModuleName ) ) ;
}
else {
2014-11-21 05:24:08 +01:00
diagnostics . push ( createDiagnosticForNode ( symbolAccesibilityResult . errorNode || errorInfo . errorNode ,
2014-10-11 01:44:14 +02:00
errorInfo . diagnosticMessage ,
symbolAccesibilityResult . errorSymbolName ,
symbolAccesibilityResult . errorModuleName ) ) ;
}
2014-08-15 23:32:08 +02:00
}
2014-08-15 23:21:41 +02:00
}
}
2014-11-21 05:24:08 +01:00
function trackSymbol ( symbol : Symbol , enclosingDeclaration? : Node , meaning? : SymbolFlags ) {
handleSymbolAccessibilityError ( resolver . isSymbolAccessible ( symbol , enclosingDeclaration , meaning ) ) ;
}
2014-08-14 23:43:28 +02:00
2014-12-06 22:53:06 +01:00
function writeTypeOfDeclaration ( declaration : AccessorDeclaration | VariableLikeDeclaration , type : TypeNode | StringLiteralExpression , getSymbolAccessibilityDiagnostic : GetSymbolAccessibilityDiagnostic ) {
2014-11-21 05:24:08 +01:00
writer . getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic ;
write ( ": " ) ;
if ( type ) {
// Write the type
emitType ( type ) ;
}
else {
2014-12-02 03:42:07 +01:00
resolver . writeTypeOfDeclaration ( declaration , enclosingDeclaration , TypeFormatFlags . UseTypeOfFunction , writer ) ;
2014-11-21 05:24:08 +01:00
}
}
2014-08-16 01:58:38 +02:00
2014-11-21 05:24:08 +01:00
function writeReturnTypeAtSignature ( signature : SignatureDeclaration , getSymbolAccessibilityDiagnostic : GetSymbolAccessibilityDiagnostic ) {
writer . getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic ;
write ( ": " ) ;
if ( signature . type ) {
// Write the type
emitType ( signature . type ) ;
2014-08-14 23:43:28 +02:00
}
else {
2014-11-21 05:24:08 +01:00
resolver . writeReturnTypeOfSignatureDeclaration ( signature , enclosingDeclaration , TypeFormatFlags . UseTypeOfFunction , writer ) ;
2014-08-14 23:43:28 +02:00
}
2014-11-21 05:24:08 +01:00
}
2014-08-14 23:43:28 +02:00
2014-10-11 01:44:14 +02:00
function emitLines ( nodes : Node [ ] ) {
for ( var i = 0 , n = nodes . length ; i < n ; i ++ ) {
2015-02-03 22:15:28 +01:00
emit ( nodes [ i ] ) ;
2014-08-14 23:43:28 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-08-14 23:43:28 +02:00
2014-11-21 05:24:08 +01:00
function emitSeparatedList ( nodes : Node [ ] , separator : string , eachNodeEmitFn : ( node : Node ) = > void ) {
2014-10-11 01:44:14 +02:00
var currentWriterPos = writer . getTextPos ( ) ;
for ( var i = 0 , n = nodes . length ; i < n ; i ++ ) {
if ( currentWriterPos !== writer . getTextPos ( ) ) {
2014-11-21 05:24:08 +01:00
write ( separator ) ;
2014-08-14 23:43:28 +02:00
}
2014-10-11 01:44:14 +02:00
currentWriterPos = writer . getTextPos ( ) ;
eachNodeEmitFn ( nodes [ i ] ) ;
2014-08-14 23:43:28 +02:00
}
2014-08-14 16:48:14 +02:00
}
2014-11-21 05:24:08 +01:00
function emitCommaList ( nodes : Node [ ] , eachNodeEmitFn : ( node : Node ) = > void ) {
emitSeparatedList ( nodes , ", " , eachNodeEmitFn ) ;
}
2014-07-13 01:04:16 +02:00
2014-11-30 23:21:34 +01:00
function writeJsDocComments ( declaration : Node ) {
2014-10-11 01:44:14 +02:00
if ( declaration ) {
var jsDocComments = getJsDocComments ( declaration , currentSourceFile ) ;
2014-10-13 19:53:57 +02:00
emitNewLineBeforeLeadingComments ( currentSourceFile , writer , declaration , jsDocComments ) ;
2014-10-11 01:44:14 +02:00
// jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space
2014-10-13 19:53:57 +02:00
emitComments ( currentSourceFile , writer , jsDocComments , /*trailingSeparator*/ true , newLine , writeCommentRange ) ;
2014-08-14 23:43:28 +02:00
}
2014-08-14 16:48:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-12-02 03:42:07 +01:00
function emitTypeWithNewGetSymbolAccessibilityDiagnostic ( type : TypeNode | EntityName , getSymbolAccessibilityDiagnostic : GetSymbolAccessibilityDiagnostic ) {
2014-11-21 05:24:08 +01:00
writer . getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic ;
emitType ( type ) ;
}
2014-07-13 01:04:16 +02:00
2014-12-02 03:42:07 +01:00
function emitType ( type : TypeNode | StringLiteralExpression | Identifier | QualifiedName ) {
2014-11-21 05:24:08 +01:00
switch ( type . kind ) {
case SyntaxKind . AnyKeyword :
case SyntaxKind . StringKeyword :
case SyntaxKind . NumberKeyword :
case SyntaxKind . BooleanKeyword :
case SyntaxKind . VoidKeyword :
case SyntaxKind . StringLiteral :
return writeTextOfNode ( currentSourceFile , type ) ;
case SyntaxKind . TypeReference :
return emitTypeReference ( < TypeReferenceNode > type ) ;
case SyntaxKind . TypeQuery :
return emitTypeQuery ( < TypeQueryNode > type ) ;
case SyntaxKind . ArrayType :
return emitArrayType ( < ArrayTypeNode > type ) ;
case SyntaxKind . TupleType :
return emitTupleType ( < TupleTypeNode > type ) ;
case SyntaxKind . UnionType :
return emitUnionType ( < UnionTypeNode > type ) ;
2014-11-30 00:52:46 +01:00
case SyntaxKind . ParenthesizedType :
return emitParenType ( < ParenthesizedTypeNode > type ) ;
2014-11-21 05:24:08 +01:00
case SyntaxKind . FunctionType :
case SyntaxKind . ConstructorType :
2014-12-02 03:42:07 +01:00
return emitSignatureDeclarationWithJsDocComments ( < FunctionOrConstructorTypeNode > type ) ;
2014-11-21 05:24:08 +01:00
case SyntaxKind . TypeLiteral :
return emitTypeLiteral ( < TypeLiteralNode > type ) ;
case SyntaxKind . Identifier :
return emitEntityName ( < Identifier > type ) ;
case SyntaxKind . QualifiedName :
return emitEntityName ( < QualifiedName > type ) ;
default :
Debug . fail ( "Unknown type annotation: " + type . kind ) ;
}
function emitEntityName ( entityName : EntityName ) {
var visibilityResult = resolver . isEntityNameVisible ( entityName ,
// Aliases can be written asynchronously so use correct enclosing declaration
2015-01-27 23:42:20 +01:00
entityName . parent . kind === SyntaxKind . ImportEqualsDeclaration ? entityName.parent : enclosingDeclaration ) ;
2014-11-21 05:24:08 +01:00
handleSymbolAccessibilityError ( visibilityResult ) ;
writeEntityName ( entityName ) ;
function writeEntityName ( entityName : EntityName ) {
if ( entityName . kind === SyntaxKind . Identifier ) {
writeTextOfNode ( currentSourceFile , entityName ) ;
}
else {
var qualifiedName = < QualifiedName > entityName ;
writeEntityName ( qualifiedName . left ) ;
write ( "." ) ;
writeTextOfNode ( currentSourceFile , qualifiedName . right ) ;
}
}
}
2014-08-12 00:54:12 +02:00
2014-11-21 05:24:08 +01:00
function emitTypeReference ( type : TypeReferenceNode ) {
emitEntityName ( type . typeName ) ;
if ( type . typeArguments ) {
write ( "<" ) ;
emitCommaList ( type . typeArguments , emitType ) ;
write ( ">" ) ;
}
}
2014-08-19 19:43:13 +02:00
2014-11-21 05:24:08 +01:00
function emitTypeQuery ( type : TypeQueryNode ) {
write ( "typeof " ) ;
emitEntityName ( type . exprName ) ;
}
2014-08-22 02:17:02 +02:00
2014-11-21 05:24:08 +01:00
function emitArrayType ( type : ArrayTypeNode ) {
emitType ( type . elementType ) ;
write ( "[]" ) ;
}
2014-08-12 00:54:12 +02:00
2014-11-21 05:24:08 +01:00
function emitTupleType ( type : TupleTypeNode ) {
write ( "[" ) ;
emitCommaList ( type . elementTypes , emitType ) ;
write ( "]" ) ;
}
2014-08-22 23:40:47 +02:00
2014-11-21 05:24:08 +01:00
function emitUnionType ( type : UnionTypeNode ) {
emitSeparatedList ( type . types , " | " , emitType ) ;
}
2014-08-12 00:54:12 +02:00
2014-11-30 00:52:46 +01:00
function emitParenType ( type : ParenthesizedTypeNode ) {
2014-11-21 05:24:08 +01:00
write ( "(" ) ;
emitType ( type . type ) ;
write ( ")" ) ;
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function emitTypeLiteral ( type : TypeLiteralNode ) {
write ( "{" ) ;
if ( type . members . length ) {
writeLine ( ) ;
increaseIndent ( ) ;
// write members
emitLines ( type . members ) ;
decreaseIndent ( ) ;
}
write ( "}" ) ;
}
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitSourceFile ( node : SourceFile ) {
currentSourceFile = node ;
enclosingDeclaration = node ;
emitLines ( node . statements ) ;
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitExportAssignment ( node : ExportAssignment ) {
write ( "export = " ) ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . exportName ) ;
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
writeLine ( ) ;
}
2014-07-13 01:04:16 +02:00
2014-11-30 23:21:34 +01:00
function emitModuleElementDeclarationFlags ( node : Node ) {
2014-11-21 05:24:08 +01:00
// If the node is parented in the current source file we need to emit export declare or just export
if ( node . parent === currentSourceFile ) {
// If the node is exported
if ( node . flags & NodeFlags . Export ) {
write ( "export " ) ;
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
if ( node . kind !== SyntaxKind . InterfaceDeclaration ) {
write ( "declare " ) ;
2014-10-11 01:44:14 +02:00
}
}
2014-11-21 05:24:08 +01:00
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function emitClassMemberDeclarationFlags ( node : Declaration ) {
if ( node . flags & NodeFlags . Private ) {
write ( "private " ) ;
}
else if ( node . flags & NodeFlags . Protected ) {
write ( "protected " ) ;
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
if ( node . flags & NodeFlags . Static ) {
write ( "static " ) ;
2014-08-14 23:43:28 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2015-01-27 23:42:20 +01:00
function emitImportEqualsDeclaration ( node : ImportEqualsDeclaration ) {
2015-02-11 02:02:11 +01:00
if ( resolver . isDeclarationVisible ( node ) ) {
2015-01-27 23:42:20 +01:00
writeImportEqualsDeclaration ( node ) ;
2014-10-11 01:44:14 +02:00
}
2015-02-11 02:02:11 +01:00
else {
aliasDeclarationEmitInfo . push ( {
declaration : node ,
outputPos : writer.getTextPos ( ) ,
indent : writer.getIndent ( ) ,
} ) ;
}
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2015-01-27 23:42:20 +01:00
function writeImportEqualsDeclaration ( node : ImportEqualsDeclaration ) {
2014-10-11 01:44:14 +02:00
// note usage of writer. methods instead of aliases created, just to make sure we are using
// correct writer especially to handle asynchronous alias writing
emitJsDocComments ( node ) ;
if ( node . flags & NodeFlags . Export ) {
2014-11-21 05:24:08 +01:00
write ( "export " ) ;
2014-10-11 01:44:14 +02:00
}
2014-11-21 05:24:08 +01:00
write ( "import " ) ;
writeTextOfNode ( currentSourceFile , node . name ) ;
write ( " = " ) ;
2015-01-27 23:42:20 +01:00
if ( isInternalModuleImportEqualsDeclaration ( node ) ) {
2014-12-02 03:42:07 +01:00
emitTypeWithNewGetSymbolAccessibilityDiagnostic ( < EntityName > node . module Reference , getImportEntityNameVisibilityError ) ;
2014-11-21 05:24:08 +01:00
write ( ";" ) ;
2014-10-11 01:44:14 +02:00
}
2014-08-14 23:43:28 +02:00
else {
2014-11-21 05:24:08 +01:00
write ( "require(" ) ;
2015-01-27 23:42:20 +01:00
writeTextOfNode ( currentSourceFile , getExternalModuleImportEqualsDeclarationExpression ( node ) ) ;
2014-11-21 05:24:08 +01:00
write ( ");" ) ;
2014-08-14 23:43:28 +02:00
}
2014-10-11 01:44:14 +02:00
writer . writeLine ( ) ;
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function getImportEntityNameVisibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) : SymbolAccessibilityDiagnostic {
return {
diagnosticMessage : Diagnostics.Import_declaration_0_is_using_private_name_1 ,
errorNode : node ,
typeName : node.name
2014-07-17 00:39:14 +02:00
} ;
2014-08-14 23:43:28 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-17 00:39:14 +02:00
2015-02-10 22:43:05 +01:00
function emitImportDeclaration ( node : ImportDeclaration ) {
2015-02-11 02:02:11 +01:00
if ( node . importClause ) {
aliasDeclarationEmitInfo . push ( {
declaration : node ,
outputPos : writer.getTextPos ( ) ,
indent : writer.getIndent ( ) ,
isVisible : ( node . importClause . name && resolver . isDeclarationVisible ( node . importClause ) ) ||
isVisibleNamedBinding ( node . importClause . namedBindings )
} ) ;
}
else {
writeImportDeclaration ( node ) ;
}
}
function isVisibleNamedBinding ( namedBindings : NamespaceImport | NamedImports ) : boolean {
if ( namedBindings ) {
if ( namedBindings . kind === SyntaxKind . NamespaceImport ) {
return resolver . isDeclarationVisible ( < NamespaceImport > namedBindings ) ;
}
else {
return forEach ( ( < NamedImports > namedBindings ) . elements , namedImport = > resolver . isDeclarationVisible ( namedImport ) ) ;
}
}
}
function writeImportDeclaration ( node : ImportDeclaration ) {
2015-02-10 22:43:05 +01:00
emitJsDocComments ( node ) ;
if ( node . flags & NodeFlags . Export ) {
write ( "export " ) ;
}
write ( "import " ) ;
2015-02-10 23:36:54 +01:00
if ( node . importClause ) {
2015-02-11 02:02:11 +01:00
var beforeDefaultBindingEmitPos = writer . getTextPos ( ) ;
if ( node . importClause . name && resolver . isDeclarationVisible ( node . importClause ) ) {
2015-02-11 00:39:24 +01:00
writeTextOfNode ( currentSourceFile , node . importClause . name ) ;
}
2015-02-11 02:02:11 +01:00
if ( node . importClause . namedBindings && isVisibleNamedBinding ( node . importClause . namedBindings ) ) {
if ( beforeDefaultBindingEmitPos !== writer . getTextPos ( ) ) {
// If the default binding was emitted, write the separated
write ( ", " ) ;
}
2015-02-10 23:36:54 +01:00
if ( node . importClause . namedBindings . kind === SyntaxKind . NamespaceImport ) {
write ( "* as " ) ;
writeTextOfNode ( currentSourceFile , ( < NamespaceImport > node . importClause . namedBindings ) . name ) ;
}
2015-02-09 17:51:55 +01:00
else {
write ( "{" ) ;
emitCommaList ( ( < NamedImports > node . importClause . namedBindings ) . elements , emitImportSpecifier ) ;
2015-02-11 02:02:11 +01:00
write ( " }" ) ;
2015-02-09 17:51:55 +01:00
}
2015-02-10 23:36:54 +01:00
}
2015-02-11 02:02:11 +01:00
write ( " from " ) ;
2015-02-10 23:36:54 +01:00
}
2015-02-10 22:43:05 +01:00
writeTextOfNode ( currentSourceFile , node . module Specifier ) ;
write ( ";" ) ;
writer . writeLine ( ) ;
}
2015-02-09 17:51:55 +01:00
function emitImportSpecifier ( node : ImportSpecifier ) {
2015-02-11 02:02:11 +01:00
if ( resolver . isDeclarationVisible ( node ) ) {
write ( " " ) ;
if ( node . propertyName ) {
writeTextOfNode ( currentSourceFile , node . propertyName ) ;
write ( " as " ) ;
}
writeTextOfNode ( currentSourceFile , node . name ) ;
2015-02-09 17:51:55 +01:00
}
}
2014-10-11 01:44:14 +02:00
function emitModuleDeclaration ( node : ModuleDeclaration ) {
if ( resolver . isDeclarationVisible ( node ) ) {
emitJsDocComments ( node ) ;
2014-11-21 05:24:08 +01:00
emitModuleElementDeclarationFlags ( node ) ;
2014-10-11 01:44:14 +02:00
write ( "module " ) ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-10-11 01:44:14 +02:00
while ( node . body . kind !== SyntaxKind . ModuleBlock ) {
node = < ModuleDeclaration > node . body ;
write ( "." ) ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
var prevEnclosingDeclaration = enclosingDeclaration ;
enclosingDeclaration = node ;
write ( " {" ) ;
writeLine ( ) ;
increaseIndent ( ) ;
2014-11-30 23:06:15 +01:00
emitLines ( ( < ModuleBlock > node . body ) . statements ) ;
2014-10-11 01:44:14 +02:00
decreaseIndent ( ) ;
write ( "}" ) ;
writeLine ( ) ;
enclosingDeclaration = prevEnclosingDeclaration ;
2014-08-14 23:43:28 +02:00
}
2014-08-14 16:48:14 +02:00
}
2014-07-17 00:39:14 +02:00
2014-11-21 05:24:08 +01:00
function emitTypeAliasDeclaration ( node : TypeAliasDeclaration ) {
if ( resolver . isDeclarationVisible ( node ) ) {
emitJsDocComments ( node ) ;
emitModuleElementDeclarationFlags ( node ) ;
write ( "type " ) ;
writeTextOfNode ( currentSourceFile , node . name ) ;
write ( " = " ) ;
2014-12-02 03:42:07 +01:00
emitTypeWithNewGetSymbolAccessibilityDiagnostic ( node . type , getTypeAliasDeclarationVisibilityError ) ;
2014-11-21 05:24:08 +01:00
write ( ";" ) ;
writeLine ( ) ;
}
function getTypeAliasDeclarationVisibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) : SymbolAccessibilityDiagnostic {
return {
diagnosticMessage : Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1 ,
errorNode : node.type ,
typeName : node.name
2014-07-17 00:39:14 +02:00
} ;
2014-11-21 05:24:08 +01:00
}
}
2014-11-26 10:06:10 +01:00
2014-10-11 01:44:14 +02:00
function emitEnumDeclaration ( node : EnumDeclaration ) {
if ( resolver . isDeclarationVisible ( node ) ) {
emitJsDocComments ( node ) ;
2014-11-21 05:24:08 +01:00
emitModuleElementDeclarationFlags ( node ) ;
2014-11-21 06:06:08 +01:00
if ( isConst ( node ) ) {
2014-11-21 05:24:08 +01:00
write ( "const " )
}
2014-10-11 01:44:14 +02:00
write ( "enum " ) ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-10-11 01:44:14 +02:00
write ( " {" ) ;
writeLine ( ) ;
increaseIndent ( ) ;
emitLines ( node . members ) ;
decreaseIndent ( ) ;
write ( "}" ) ;
writeLine ( ) ;
}
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
function emitEnumMemberDeclaration ( node : EnumMember ) {
emitJsDocComments ( node ) ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2015-02-06 03:26:56 +01:00
var enumMemberValue = resolver . getConstantValue ( node ) ;
2014-10-11 01:44:14 +02:00
if ( enumMemberValue !== undefined ) {
write ( " = " ) ;
write ( enumMemberValue . toString ( ) ) ;
}
write ( "," ) ;
writeLine ( ) ;
}
2014-07-17 00:39:14 +02:00
2014-12-09 01:16:11 +01:00
function isPrivateMethodTypeParameter ( node : TypeParameterDeclaration ) {
return node . parent . kind === SyntaxKind . MethodDeclaration && ( node . parent . flags & NodeFlags . Private ) ;
}
2014-10-11 01:44:14 +02:00
function emitTypeParameters ( typeParameters : TypeParameterDeclaration [ ] ) {
function emitTypeParameter ( node : TypeParameterDeclaration ) {
2014-11-21 05:24:08 +01:00
increaseIndent ( ) ;
emitJsDocComments ( node ) ;
decreaseIndent ( ) ;
writeTextOfNode ( currentSourceFile , node . name ) ;
// If there is constraint present and this is not a type parameter of the private method emit the constraint
2014-12-09 01:16:11 +01:00
if ( node . constraint && ! isPrivateMethodTypeParameter ( node ) ) {
2014-11-21 05:24:08 +01:00
write ( " extends " ) ;
if ( node . parent . kind === SyntaxKind . FunctionType ||
node . parent . kind === SyntaxKind . ConstructorType ||
( node . parent . parent && node . parent . parent . kind === SyntaxKind . TypeLiteral ) ) {
2014-12-09 01:16:11 +01:00
Debug . assert ( node . parent . kind === SyntaxKind . MethodDeclaration ||
node . parent . kind === SyntaxKind . MethodSignature ||
2014-11-21 05:24:08 +01:00
node . parent . kind === SyntaxKind . FunctionType ||
node . parent . kind === SyntaxKind . ConstructorType ||
node . parent . kind === SyntaxKind . CallSignature ||
node . parent . kind === SyntaxKind . ConstructSignature ) ;
emitType ( node . constraint ) ;
2014-07-17 00:39:14 +02:00
}
else {
2014-12-02 03:42:07 +01:00
emitTypeWithNewGetSymbolAccessibilityDiagnostic ( node . constraint , getTypeParameterConstraintVisibilityError ) ;
2014-07-17 00:39:14 +02:00
}
2014-11-21 05:24:08 +01:00
}
2014-07-16 19:49:11 +02:00
2014-11-21 05:24:08 +01:00
function getTypeParameterConstraintVisibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) : SymbolAccessibilityDiagnostic {
2014-10-11 01:44:14 +02:00
// Type parameter constraints are named by user so we should always be able to name it
var diagnosticMessage : DiagnosticMessage ;
switch ( node . parent . kind ) {
case SyntaxKind . ClassDeclaration :
2014-11-21 05:24:08 +01:00
diagnosticMessage = Diagnostics . Type_parameter_0_of_exported_class_has_or_is_using_private_name_1 ;
2014-10-11 01:44:14 +02:00
break ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . InterfaceDeclaration :
2014-11-21 05:24:08 +01:00
diagnosticMessage = Diagnostics . Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1 ;
2014-10-11 01:44:14 +02:00
break ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . ConstructSignature :
2014-11-21 05:24:08 +01:00
diagnosticMessage = Diagnostics . Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1 ;
2014-10-11 01:44:14 +02:00
break ;
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . CallSignature :
2014-11-21 05:24:08 +01:00
diagnosticMessage = Diagnostics . Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1 ;
2014-10-11 01:44:14 +02:00
break ;
2014-07-13 01:04:16 +02:00
2014-12-09 01:16:11 +01:00
case SyntaxKind . MethodDeclaration :
case SyntaxKind . MethodSignature :
2014-10-11 01:44:14 +02:00
if ( node . parent . flags & NodeFlags . Static ) {
2014-11-21 05:24:08 +01:00
diagnosticMessage = Diagnostics . Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else if ( node . parent . parent . kind === SyntaxKind . ClassDeclaration ) {
2014-11-21 05:24:08 +01:00
diagnosticMessage = Diagnostics . Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else {
2014-11-21 05:24:08 +01:00
diagnosticMessage = Diagnostics . Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1 ;
2014-10-11 01:44:14 +02:00
}
break ;
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . FunctionDeclaration :
2014-11-21 05:24:08 +01:00
diagnosticMessage = Diagnostics . Type_parameter_0_of_exported_function_has_or_is_using_private_name_1 ;
2014-10-11 01:44:14 +02:00
break ;
2014-08-22 23:40:47 +02:00
2014-10-11 01:44:14 +02:00
default :
2014-11-21 05:24:08 +01:00
Debug . fail ( "This is unknown parent for type parameter: " + node . parent . kind ) ;
2014-07-13 01:04:16 +02:00
}
2014-08-12 00:54:12 +02:00
2014-10-11 01:44:14 +02:00
return {
2014-11-21 05:24:08 +01:00
diagnosticMessage ,
2014-10-11 01:44:14 +02:00
errorNode : node ,
typeName : node.name
} ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
if ( typeParameters ) {
write ( "<" ) ;
emitCommaList ( typeParameters , emitTypeParameter ) ;
write ( ">" ) ;
}
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
function emitHeritageClause ( typeReferences : TypeReferenceNode [ ] , isImplementsList : boolean ) {
if ( typeReferences ) {
write ( isImplementsList ? " implements " : " extends " ) ;
emitCommaList ( typeReferences , emitTypeOfTypeReference ) ;
}
2014-07-17 00:39:14 +02:00
2014-12-02 03:42:07 +01:00
function emitTypeOfTypeReference ( node : TypeReferenceNode ) {
emitTypeWithNewGetSymbolAccessibilityDiagnostic ( node , getHeritageClauseVisibilityError ) ;
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function getHeritageClauseVisibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) : SymbolAccessibilityDiagnostic {
2014-10-11 01:44:14 +02:00
var diagnosticMessage : DiagnosticMessage ;
// Heritage clause is written by user so it can always be named
2014-12-01 00:38:45 +01:00
if ( node . parent . parent . kind === SyntaxKind . ClassDeclaration ) {
2014-11-21 05:24:08 +01:00
// Class or Interface implemented/extended is inaccessible
diagnosticMessage = isImplementsList ?
2014-12-01 00:38:45 +01:00
Diagnostics . Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 :
Diagnostics . Extends_clause_of_exported_class_0_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
else {
2014-11-21 05:24:08 +01:00
// interface is inaccessible
diagnosticMessage = Diagnostics . Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1 ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
return {
2014-11-21 05:24:08 +01:00
diagnosticMessage ,
2014-10-11 01:44:14 +02:00
errorNode : node ,
2014-12-01 00:38:45 +01:00
typeName : ( < Declaration > node . parent . parent ) . name
2014-10-11 01:44:14 +02:00
} ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
}
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
function emitClassDeclaration ( node : ClassDeclaration ) {
function emitParameterProperties ( constructorDeclaration : ConstructorDeclaration ) {
if ( constructorDeclaration ) {
forEach ( constructorDeclaration . parameters , param = > {
if ( param . flags & NodeFlags . AccessibilityModifier ) {
emitPropertyDeclaration ( param ) ;
}
} ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
if ( resolver . isDeclarationVisible ( node ) ) {
emitJsDocComments ( node ) ;
2014-11-21 05:24:08 +01:00
emitModuleElementDeclarationFlags ( node ) ;
2014-10-11 01:44:14 +02:00
write ( "class " ) ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-10-11 01:44:14 +02:00
var prevEnclosingDeclaration = enclosingDeclaration ;
enclosingDeclaration = node ;
emitTypeParameters ( node . typeParameters ) ;
2014-12-01 00:38:45 +01:00
var baseTypeNode = getClassBaseTypeNode ( node ) ;
if ( baseTypeNode ) {
emitHeritageClause ( [ baseTypeNode ] , /*isImplementsList*/ false ) ;
2014-07-17 00:39:14 +02:00
}
2014-12-01 00:38:45 +01:00
emitHeritageClause ( getClassImplementedTypeNodes ( node ) , /*isImplementsList*/ true ) ;
2014-10-11 01:44:14 +02:00
write ( " {" ) ;
writeLine ( ) ;
increaseIndent ( ) ;
emitParameterProperties ( getFirstConstructorWithBody ( node ) ) ;
emitLines ( node . members ) ;
decreaseIndent ( ) ;
write ( "}" ) ;
writeLine ( ) ;
enclosingDeclaration = prevEnclosingDeclaration ;
}
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitInterfaceDeclaration ( node : InterfaceDeclaration ) {
if ( resolver . isDeclarationVisible ( node ) ) {
emitJsDocComments ( node ) ;
2014-11-21 05:24:08 +01:00
emitModuleElementDeclarationFlags ( node ) ;
2014-10-11 01:44:14 +02:00
write ( "interface " ) ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-10-11 01:44:14 +02:00
var prevEnclosingDeclaration = enclosingDeclaration ;
enclosingDeclaration = node ;
emitTypeParameters ( node . typeParameters ) ;
2014-12-01 00:38:45 +01:00
emitHeritageClause ( getInterfaceBaseTypeNodes ( node ) , /*isImplementsList*/ false ) ;
2014-10-11 01:44:14 +02:00
write ( " {" ) ;
writeLine ( ) ;
increaseIndent ( ) ;
emitLines ( node . members ) ;
decreaseIndent ( ) ;
write ( "}" ) ;
writeLine ( ) ;
enclosingDeclaration = prevEnclosingDeclaration ;
}
}
2014-07-13 01:04:16 +02:00
2014-11-30 23:28:32 +01:00
function emitPropertyDeclaration ( node : Declaration ) {
2015-01-23 04:09:10 +01:00
if ( hasDynamicName ( node ) ) {
2015-01-21 03:29:04 +01:00
return ;
}
2014-10-11 01:44:14 +02:00
emitJsDocComments ( node ) ;
2014-11-21 05:24:08 +01:00
emitClassMemberDeclarationFlags ( node ) ;
emitVariableDeclaration ( < VariableDeclaration > node ) ;
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
writeLine ( ) ;
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitVariableDeclaration ( node : VariableDeclaration ) {
// If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
// so there is no check needed to see if declaration is visible
if ( node . kind !== SyntaxKind . VariableDeclaration || resolver . isDeclarationVisible ( node ) ) {
2015-01-21 03:29:04 +01:00
// If this node is a computed name, it can only be a symbol, because we've already skipped
// it if it's not a well known symbol. In that case, the text of the name will be exactly
// what we want, namely the name expression enclosed in brackets.
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-10-11 01:44:14 +02:00
// If optional property emit ?
2014-12-09 01:37:35 +01:00
if ( ( node . kind === SyntaxKind . PropertyDeclaration || node . kind === SyntaxKind . PropertySignature ) && hasQuestionToken ( node ) ) {
2014-10-11 01:44:14 +02:00
write ( "?" ) ;
2014-07-13 01:04:16 +02:00
}
2014-12-09 01:37:35 +01:00
if ( ( node . kind === SyntaxKind . PropertyDeclaration || node . kind === SyntaxKind . PropertySignature ) && node . parent . kind === SyntaxKind . TypeLiteral ) {
2014-11-21 05:24:08 +01:00
emitTypeOfVariableDeclarationFromTypeLiteral ( node ) ;
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
else if ( ! ( node . flags & NodeFlags . Private ) ) {
2014-12-02 03:42:07 +01:00
writeTypeOfDeclaration ( node , node . type , getVariableDeclarationTypeVisibilityError ) ;
2014-10-11 01:44:14 +02:00
}
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function getVariableDeclarationTypeVisibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) : SymbolAccessibilityDiagnostic {
2014-10-11 01:44:14 +02:00
var diagnosticMessage : DiagnosticMessage ;
if ( node . kind === SyntaxKind . VariableDeclaration ) {
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics . Exported_variable_0_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Exported_variable_0_has_or_is_using_private_name_1 ;
}
// This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
2014-12-09 01:37:35 +01:00
else if ( node . kind === SyntaxKind . PropertyDeclaration || node . kind === SyntaxKind . PropertySignature ) {
2014-11-21 05:24:08 +01:00
// TODO(jfreeman): Deal with computed properties in error reporting.
2014-10-11 01:44:14 +02:00
if ( node . flags & NodeFlags . Static ) {
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics . Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Public_static_property_0_of_exported_class_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else if ( node . parent . kind === SyntaxKind . ClassDeclaration ) {
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics . Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Public_property_0_of_exported_class_has_or_is_using_private_name_1 ;
2014-07-13 01:04:16 +02:00
}
else {
2014-10-11 01:44:14 +02:00
// Interfaces cannot have types that cannot be named
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Property_0_of_exported_interface_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
return diagnosticMessage !== undefined ? {
2014-11-21 05:24:08 +01:00
diagnosticMessage ,
2014-10-11 01:44:14 +02:00
errorNode : node ,
typeName : node.name
} : undefined ;
}
}
2014-07-13 01:04:16 +02:00
2014-12-06 22:53:06 +01:00
function emitTypeOfVariableDeclarationFromTypeLiteral ( node : VariableLikeDeclaration ) {
2014-11-21 05:24:08 +01:00
// if this is property of type literal,
// or is parameter of method/call/construct/index signature of type literal
// emit only if type is specified
if ( node . type ) {
write ( ": " ) ;
emitType ( node . type ) ;
}
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitVariableStatement ( node : VariableStatement ) {
2014-12-16 10:09:42 +01:00
var hasDeclarationWithEmit = forEach ( node . declarationList . declarations , varDeclaration = > resolver . isDeclarationVisible ( varDeclaration ) ) ;
2014-10-11 01:44:14 +02:00
if ( hasDeclarationWithEmit ) {
emitJsDocComments ( node ) ;
2014-11-21 05:24:08 +01:00
emitModuleElementDeclarationFlags ( node ) ;
2014-12-16 10:09:42 +01:00
if ( isLet ( node . declarationList ) ) {
2014-11-21 05:24:08 +01:00
write ( "let " ) ;
2014-07-13 01:04:16 +02:00
}
2014-12-16 10:09:42 +01:00
else if ( isConst ( node . declarationList ) ) {
2014-11-21 05:24:08 +01:00
write ( "const " ) ;
2014-08-12 00:54:12 +02:00
}
2014-07-13 01:04:16 +02:00
else {
2014-11-21 05:24:08 +01:00
write ( "var " ) ;
2014-07-13 01:04:16 +02:00
}
2014-12-16 10:09:42 +01:00
emitCommaList ( node . declarationList . declarations , emitVariableDeclaration ) ;
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
writeLine ( ) ;
}
}
2014-08-12 00:54:12 +02:00
2014-10-11 01:44:14 +02:00
function emitAccessorDeclaration ( node : AccessorDeclaration ) {
2015-01-23 04:09:10 +01:00
if ( hasDynamicName ( node ) ) {
2015-01-21 03:29:04 +01:00
return ;
}
2014-10-11 01:44:14 +02:00
var accessors = getAllAccessorDeclarations ( < ClassDeclaration > node . parent , node ) ;
if ( node === accessors . firstAccessor ) {
emitJsDocComments ( accessors . getAccessor ) ;
emitJsDocComments ( accessors . setAccessor ) ;
2014-11-21 05:24:08 +01:00
emitClassMemberDeclarationFlags ( node ) ;
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-10-11 01:44:14 +02:00
if ( ! ( node . flags & NodeFlags . Private ) ) {
2014-11-21 05:24:08 +01:00
var accessorWithTypeAnnotation : AccessorDeclaration = node ;
var type = getTypeAnnotationFromAccessor ( node ) ;
if ( ! type ) {
// couldn't get type for the first accessor, try the another one
var anotherAccessor = node . kind === SyntaxKind . GetAccessor ? accessors.setAccessor : accessors.getAccessor ;
type = getTypeAnnotationFromAccessor ( anotherAccessor ) ;
if ( type ) {
accessorWithTypeAnnotation = anotherAccessor ;
2014-09-22 20:50:31 +02:00
}
}
2014-12-02 03:42:07 +01:00
writeTypeOfDeclaration ( node , type , getAccessorDeclarationTypeVisibilityError ) ;
2014-09-20 00:09:04 +02:00
}
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
writeLine ( ) ;
2014-07-13 01:04:16 +02:00
}
2014-09-20 00:09:04 +02:00
2014-12-02 03:42:07 +01:00
function getTypeAnnotationFromAccessor ( accessor : AccessorDeclaration ) : TypeNode | StringLiteralExpression {
2014-11-21 05:24:08 +01:00
if ( accessor ) {
2014-12-02 03:42:07 +01:00
return accessor . kind === SyntaxKind . GetAccessor
? accessor . type // Getter - return type
2015-02-05 23:41:04 +01:00
: accessor . parameters . length > 0
? accessor . parameters [ 0 ] . type // Setter parameter type
: undefined ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
2014-11-21 05:24:08 +01:00
function getAccessorDeclarationTypeVisibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) : SymbolAccessibilityDiagnostic {
2014-10-11 01:44:14 +02:00
var diagnosticMessage : DiagnosticMessage ;
2014-11-21 05:24:08 +01:00
if ( accessorWithTypeAnnotation . kind === SyntaxKind . SetAccessor ) {
2014-10-11 01:44:14 +02:00
// Setters have to have type named and cannot infer it so, the type should always be named
2014-11-21 05:24:08 +01:00
if ( accessorWithTypeAnnotation . parent . flags & NodeFlags . Static ) {
2014-10-11 01:44:14 +02:00
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
else {
2014-10-11 01:44:14 +02:00
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
return {
2014-11-21 05:24:08 +01:00
diagnosticMessage ,
errorNode : < Node > accessorWithTypeAnnotation . parameters [ 0 ] ,
// TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name
typeName : accessorWithTypeAnnotation.name
2014-10-11 01:44:14 +02:00
} ;
2014-07-13 01:04:16 +02:00
}
else {
2014-11-21 05:24:08 +01:00
if ( accessorWithTypeAnnotation . flags & NodeFlags . Static ) {
2014-10-11 01:44:14 +02:00
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
Diagnostics . Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0 ;
2014-07-17 00:39:14 +02:00
}
else {
2014-10-11 01:44:14 +02:00
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
Diagnostics . Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0 ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
return {
2014-11-21 05:24:08 +01:00
diagnosticMessage ,
errorNode : < Node > accessorWithTypeAnnotation . name ,
2014-10-11 01:44:14 +02:00
typeName : undefined
} ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function emitFunctionDeclaration ( node : FunctionLikeDeclaration ) {
2015-01-23 04:09:10 +01:00
if ( hasDynamicName ( node ) ) {
2015-01-21 03:29:04 +01:00
return ;
}
2014-10-11 01:44:14 +02:00
// If we are emitting Method/Constructor it isn't moduleElement and hence already determined to be emitting
// so no need to verify if the declaration is visible
if ( ( node . kind !== SyntaxKind . FunctionDeclaration || resolver . isDeclarationVisible ( node ) ) &&
! resolver . isImplementationOfOverload ( node ) ) {
emitJsDocComments ( node ) ;
2014-11-21 05:24:08 +01:00
if ( node . kind === SyntaxKind . FunctionDeclaration ) {
emitModuleElementDeclarationFlags ( node ) ;
2014-11-28 19:13:52 +01:00
}
2014-12-09 01:16:11 +01:00
else if ( node . kind === SyntaxKind . MethodDeclaration ) {
2014-11-21 05:24:08 +01:00
emitClassMemberDeclarationFlags ( node ) ;
2014-12-02 20:39:04 +01:00
}
2014-10-11 01:44:14 +02:00
if ( node . kind === SyntaxKind . FunctionDeclaration ) {
write ( "function " ) ;
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-12-02 20:39:04 +01:00
}
2014-10-11 01:44:14 +02:00
else if ( node . kind === SyntaxKind . Constructor ) {
write ( "constructor" ) ;
2014-07-17 00:39:14 +02:00
}
else {
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node . name ) ;
2014-12-02 07:03:41 +01:00
if ( hasQuestionToken ( node ) ) {
2014-10-11 01:44:14 +02:00
write ( "?" ) ;
2014-09-24 19:36:44 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
emitSignatureDeclaration ( node ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
function emitSignatureDeclarationWithJsDocComments ( node : SignatureDeclaration ) {
2014-10-11 01:44:14 +02:00
emitJsDocComments ( node ) ;
emitSignatureDeclaration ( node ) ;
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitSignatureDeclaration ( node : SignatureDeclaration ) {
2014-11-21 05:24:08 +01:00
// Construct signature or constructor type write new Signature
if ( node . kind === SyntaxKind . ConstructSignature || node . kind === SyntaxKind . ConstructorType ) {
write ( "new " ) ;
2014-09-24 19:36:44 +02:00
}
2014-10-11 01:44:14 +02:00
emitTypeParameters ( node . typeParameters ) ;
if ( node . kind === SyntaxKind . IndexSignature ) {
write ( "[" ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else {
write ( "(" ) ;
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
var prevEnclosingDeclaration = enclosingDeclaration ;
enclosingDeclaration = node ;
2014-07-18 02:43:48 +02:00
2014-10-11 01:44:14 +02:00
// Parameters
emitCommaList ( node . parameters , emitParameterDeclaration ) ;
2014-10-16 02:12:13 +02:00
2014-10-11 01:44:14 +02:00
if ( node . kind === SyntaxKind . IndexSignature ) {
write ( "]" ) ;
}
else {
write ( ")" ) ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// If this is not a constructor and is not private, emit the return type
2014-11-21 05:24:08 +01:00
var isFunctionTypeOrConstructorType = node . kind === SyntaxKind . FunctionType || node . kind === SyntaxKind . ConstructorType ;
if ( isFunctionTypeOrConstructorType || node . parent . kind === SyntaxKind . TypeLiteral ) {
// Emit type literal signature return type only if specified
if ( node . type ) {
write ( isFunctionTypeOrConstructorType ? " => " : ": " ) ;
emitType ( node . type ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-16 02:12:13 +02:00
}
2014-11-21 05:24:08 +01:00
else if ( node . kind !== SyntaxKind . Constructor && ! ( node . flags & NodeFlags . Private ) ) {
writeReturnTypeAtSignature ( node , getReturnTypeVisibilityError ) ;
2014-10-16 02:12:13 +02:00
}
2014-11-21 05:24:08 +01:00
enclosingDeclaration = prevEnclosingDeclaration ;
2014-10-28 00:21:06 +01:00
2014-11-21 05:24:08 +01:00
if ( ! isFunctionTypeOrConstructorType ) {
write ( ";" ) ;
writeLine ( ) ;
2014-10-16 02:12:13 +02:00
}
2014-10-28 00:21:06 +01:00
2014-11-21 05:24:08 +01:00
function getReturnTypeVisibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) : SymbolAccessibilityDiagnostic {
2014-10-11 01:44:14 +02:00
var diagnosticMessage : DiagnosticMessage ;
switch ( node . kind ) {
case SyntaxKind . ConstructSignature :
// Interfaces cannot have return types that cannot be named
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0 ;
break ;
2014-10-16 02:12:13 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . CallSignature :
// Interfaces cannot have return types that cannot be named
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0 ;
break ;
2014-10-16 02:12:13 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . IndexSignature :
// Interfaces cannot have return types that cannot be named
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0 ;
break ;
2014-10-16 02:12:13 +02:00
2014-12-09 01:16:11 +01:00
case SyntaxKind . MethodDeclaration :
case SyntaxKind . MethodSignature :
2014-10-11 01:44:14 +02:00
if ( node . flags & NodeFlags . Static ) {
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
Diagnostics . Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0 ;
2014-09-22 20:50:31 +02:00
}
2014-10-11 01:44:14 +02:00
else if ( node . parent . kind === SyntaxKind . ClassDeclaration ) {
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
Diagnostics . Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0 ;
}
else {
// Interfaces cannot have return types that cannot be named
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0 ;
}
break ;
2014-10-16 02:12:13 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . FunctionDeclaration :
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
Diagnostics . Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 :
Diagnostics . Return_type_of_exported_function_has_or_is_using_private_name_0 ;
break ;
2014-10-16 02:12:13 +02:00
2014-10-11 01:44:14 +02:00
default :
2014-11-21 05:24:08 +01:00
Debug . fail ( "This is unknown kind for signature: " + node . kind ) ;
2014-10-16 02:12:13 +02:00
}
2014-10-11 01:44:14 +02:00
return {
2014-11-21 05:24:08 +01:00
diagnosticMessage ,
2014-10-11 01:44:14 +02:00
errorNode : < Node > node . name || node ,
2014-07-17 00:39:14 +02:00
} ;
2014-10-11 01:44:14 +02:00
}
}
2014-11-20 02:04:34 +01:00
2014-10-11 01:44:14 +02:00
function emitParameterDeclaration ( node : ParameterDeclaration ) {
increaseIndent ( ) ;
emitJsDocComments ( node ) ;
2014-12-02 04:19:50 +01:00
if ( node . dotDotDotToken ) {
2014-10-11 01:44:14 +02:00
write ( "..." ) ;
}
2014-12-04 01:43:01 +01:00
if ( isBindingPattern ( node . name ) ) {
write ( "_" + indexOf ( ( < FunctionLikeDeclaration > node . parent ) . parameters , node ) ) ;
}
else {
writeTextOfNode ( currentSourceFile , node . name ) ;
}
2014-12-02 07:03:41 +01:00
if ( node . initializer || hasQuestionToken ( node ) ) {
2014-10-11 01:44:14 +02:00
write ( "?" ) ;
2014-10-16 02:12:13 +02:00
}
2014-10-11 01:44:14 +02:00
decreaseIndent ( ) ;
2014-10-16 02:12:13 +02:00
2014-11-21 05:24:08 +01:00
if ( node . parent . kind === SyntaxKind . FunctionType ||
node . parent . kind === SyntaxKind . ConstructorType ||
node . parent . parent . kind === SyntaxKind . TypeLiteral ) {
emitTypeOfVariableDeclarationFromTypeLiteral ( node ) ;
}
else if ( ! ( node . parent . flags & NodeFlags . Private ) ) {
2014-12-02 03:42:07 +01:00
writeTypeOfDeclaration ( node , node . type , getParameterDeclarationTypeVisibilityError ) ;
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
function getParameterDeclarationTypeVisibilityError ( symbolAccesibilityResult : SymbolAccessiblityResult ) : SymbolAccessibilityDiagnostic {
2014-10-11 01:44:14 +02:00
var diagnosticMessage : DiagnosticMessage ;
switch ( node . parent . kind ) {
case SyntaxKind . Constructor :
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics . Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1 ;
break ;
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . ConstructSignature :
// Interfaces cannot have parameter types that cannot be named
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1 ;
break ;
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
case SyntaxKind . CallSignature :
// Interfaces cannot have parameter types that cannot be named
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1 ;
break ;
2014-07-17 00:39:14 +02:00
2014-12-09 01:16:11 +01:00
case SyntaxKind . MethodDeclaration :
case SyntaxKind . MethodSignature :
2014-10-11 01:44:14 +02:00
if ( node . parent . flags & NodeFlags . Static ) {
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics . Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1 ;
}
else if ( node . parent . parent . kind === SyntaxKind . ClassDeclaration ) {
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics . Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
else {
2014-10-11 01:44:14 +02:00
// Interfaces cannot have parameter types that cannot be named
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
Diagnostics . Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1 ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
break ;
2014-07-17 00:39:14 +02:00
case SyntaxKind . FunctionDeclaration :
2014-10-11 01:44:14 +02:00
diagnosticMessage = symbolAccesibilityResult . errorModuleName ?
symbolAccesibilityResult . accessibility === SymbolAccessibility . CannotBeNamed ?
Diagnostics . Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics . Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 :
Diagnostics . Parameter_0_of_exported_function_has_or_is_using_private_name_1 ;
break ;
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
default :
2014-11-21 05:24:08 +01:00
Debug . fail ( "This is unknown parent for parameter: " + node . parent . kind ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
return {
2014-11-21 05:24:08 +01:00
diagnosticMessage ,
2014-10-11 01:44:14 +02:00
errorNode : node ,
typeName : node.name
} ;
2014-11-13 20:33:31 +01:00
}
2014-10-11 01:44:14 +02:00
}
2014-11-13 20:33:31 +01:00
2014-10-11 01:44:14 +02:00
function emitNode ( node : Node ) {
switch ( node . kind ) {
case SyntaxKind . Constructor :
case SyntaxKind . FunctionDeclaration :
2014-12-09 01:16:11 +01:00
case SyntaxKind . MethodDeclaration :
case SyntaxKind . MethodSignature :
2014-11-21 05:24:08 +01:00
return emitFunctionDeclaration ( < FunctionLikeDeclaration > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . ConstructSignature :
case SyntaxKind . CallSignature :
case SyntaxKind . IndexSignature :
2014-11-21 05:24:08 +01:00
return emitSignatureDeclarationWithJsDocComments ( < SignatureDeclaration > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . GetAccessor :
case SyntaxKind . SetAccessor :
return emitAccessorDeclaration ( < AccessorDeclaration > node ) ;
case SyntaxKind . VariableStatement :
return emitVariableStatement ( < VariableStatement > node ) ;
2014-12-09 01:37:35 +01:00
case SyntaxKind . PropertyDeclaration :
case SyntaxKind . PropertySignature :
2014-10-11 01:44:14 +02:00
return emitPropertyDeclaration ( < PropertyDeclaration > node ) ;
case SyntaxKind . InterfaceDeclaration :
return emitInterfaceDeclaration ( < InterfaceDeclaration > node ) ;
case SyntaxKind . ClassDeclaration :
return emitClassDeclaration ( < ClassDeclaration > node ) ;
2014-11-21 05:24:08 +01:00
case SyntaxKind . TypeAliasDeclaration :
return emitTypeAliasDeclaration ( < TypeAliasDeclaration > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . EnumMember :
return emitEnumMemberDeclaration ( < EnumMember > node ) ;
case SyntaxKind . EnumDeclaration :
return emitEnumDeclaration ( < EnumDeclaration > node ) ;
case SyntaxKind . ModuleDeclaration :
return emitModuleDeclaration ( < ModuleDeclaration > node ) ;
2015-01-27 23:42:20 +01:00
case SyntaxKind . ImportEqualsDeclaration :
return emitImportEqualsDeclaration ( < ImportEqualsDeclaration > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . ExportAssignment :
return emitExportAssignment ( < ExportAssignment > node ) ;
2015-02-10 22:43:05 +01:00
case SyntaxKind . ImportDeclaration :
return emitImportDeclaration ( < ImportDeclaration > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . SourceFile :
return emitSourceFile ( < SourceFile > node ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function writeReferencePath ( referencedFile : SourceFile ) {
var declFileName = referencedFile . flags & NodeFlags . DeclarationFile
2015-02-04 01:08:46 +01:00
? referencedFile . fileName // Declaration file, use declaration file name
2014-10-11 01:44:14 +02:00
: shouldEmitToOwnFile ( referencedFile , compilerOptions )
2014-12-16 22:52:47 +01:00
? getOwnEmitOutputFilePath ( referencedFile , host , ".d.ts" ) // Own output file so get the .d.ts file
: removeFileExtension ( compilerOptions . out ) + ".d.ts" ; // Global out file
2014-10-11 01:44:14 +02:00
declFileName = getRelativePathToDirectoryOrUrl (
getDirectoryPath ( normalizeSlashes ( jsFilePath ) ) ,
declFileName ,
2014-12-16 23:42:58 +01:00
host . getCurrentDirectory ( ) ,
host . getCanonicalFileName ,
2014-10-11 01:44:14 +02:00
/*isAbsolutePathAnUrl*/ false ) ;
referencePathsOutput += "/// <reference path=\"" + declFileName + "\" />" + newLine ;
}
}
2014-12-22 22:58:14 +01:00
2014-12-16 23:42:58 +01:00
export function getDeclarationDiagnostics ( host : EmitHost , resolver : EmitResolver , targetSourceFile : SourceFile ) : Diagnostic [ ] {
2014-10-13 21:41:26 +02:00
var diagnostics : Diagnostic [ ] = [ ] ;
2014-12-16 23:42:58 +01:00
var jsFilePath = getOwnEmitOutputFilePath ( targetSourceFile , host , ".js" ) ;
emitDeclarations ( host , resolver , diagnostics , jsFilePath , targetSourceFile ) ;
2014-10-13 21:41:26 +02:00
return diagnostics ;
}
2014-07-13 01:04:16 +02:00
2015-02-05 01:53:14 +01:00
// @internal
2015-02-06 03:26:56 +01:00
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
2015-02-06 02:11:06 +01:00
export function emitFiles ( resolver : EmitResolver , host : EmitHost , targetSourceFile : SourceFile ) : EmitResult {
2014-12-16 22:52:47 +01:00
var compilerOptions = host . getCompilerOptions ( ) ;
2015-01-16 16:15:31 +01:00
var languageVersion = compilerOptions . target || ScriptTarget . ES3 ;
2014-10-11 01:44:14 +02:00
var sourceMapDataList : SourceMapData [ ] = compilerOptions . sourceMap ? [ ] : undefined ;
var diagnostics : Diagnostic [ ] = [ ] ;
2014-12-16 23:42:58 +01:00
var newLine = host . getNewLine ( ) ;
2014-11-13 20:33:31 +01:00
2015-02-05 23:46:50 +01:00
if ( targetSourceFile === undefined ) {
forEach ( host . getSourceFiles ( ) , sourceFile = > {
if ( shouldEmitToOwnFile ( sourceFile , compilerOptions ) ) {
var jsFilePath = getOwnEmitOutputFilePath ( sourceFile , host , ".js" ) ;
emitFile ( jsFilePath , sourceFile ) ;
}
} ) ;
if ( compilerOptions . out ) {
emitFile ( compilerOptions . out ) ;
}
}
else {
// targetSourceFile is specified (e.g calling emitter from language service or calling getSemanticDiagnostic from language service)
if ( shouldEmitToOwnFile ( targetSourceFile , compilerOptions ) ) {
var jsFilePath = getOwnEmitOutputFilePath ( targetSourceFile , host , ".js" ) ;
emitFile ( jsFilePath , targetSourceFile ) ;
}
else if ( ! isDeclarationFile ( targetSourceFile ) && compilerOptions . out ) {
emitFile ( compilerOptions . out ) ;
}
}
// Sort and make the unique list of diagnostics
diagnostics = sortAndDeduplicateDiagnostics ( diagnostics ) ;
return {
2015-02-06 00:50:18 +01:00
emitSkipped : false ,
2015-02-05 23:46:50 +01:00
diagnostics ,
sourceMaps : sourceMapDataList
} ;
2014-10-11 01:44:14 +02:00
function emitJavaScript ( jsFilePath : string , root? : SourceFile ) {
2014-11-21 05:24:08 +01:00
var writer = createTextWriter ( newLine ) ;
2014-10-11 01:44:14 +02:00
var write = writer . write ;
2014-11-21 05:24:08 +01:00
var writeTextOfNode = writer . writeTextOfNode ;
2014-10-11 01:44:14 +02:00
var writeLine = writer . writeLine ;
var increaseIndent = writer . increaseIndent ;
var decreaseIndent = writer . decreaseIndent ;
2014-11-04 23:43:43 +01:00
2014-10-11 01:44:14 +02:00
var currentSourceFile : SourceFile ;
2014-11-02 02:16:48 +01:00
2014-10-11 01:44:14 +02:00
var extendsEmitted = false ;
2014-12-04 01:43:01 +01:00
var tempCount = 0 ;
var tempVariables : Identifier [ ] ;
var tempParameters : Identifier [ ] ;
2015-02-08 17:03:15 +01:00
var externalImports : ExternalImportInfo [ ] ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
/** write emitted output to disk*/
var writeEmittedFiles = writeJavaScriptFile ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
/** Emit leading comments of the node */
var emitLeadingComments = compilerOptions . removeComments ? ( node : Node ) = > { } : emitLeadingDeclarationComments ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
/** Emit Trailing comments of the node */
var emitTrailingComments = compilerOptions . removeComments ? ( node : Node ) = > { } : emitTrailingDeclarationComments ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
var emitLeadingCommentsOfPosition = compilerOptions . removeComments ? ( pos : number ) = > { } : emitLeadingCommentsOfLocalPosition ;
2014-10-24 01:32:43 +02:00
2014-10-11 01:44:14 +02:00
var detachedCommentsInfo : { nodePos : number ; detachedCommentEndPos : number } [ ] ;
/** Emit detached comments of the node */
var emitDetachedComments = compilerOptions . removeComments ? ( node : TextRange ) = > { } : emitDetachedCommentsAtPosition ;
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
/** Emits /// or pinned which is comment starting with /*! comments */
var emitPinnedOrTripleSlashComments = compilerOptions . removeComments ? ( node : Node ) = > { } : emitPinnedOrTripleSlashCommentsOfNode ;
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
var writeComment = writeCommentRange ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
/** Emit a node */
var emit = emitNode ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
/** Called just before starting emit of a node */
var emitStart = function ( node : Node ) { } ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
/** Called once the emit of the node is done */
var emitEnd = function ( node : Node ) { } ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
/ * * E m i t t h e t e x t f o r t h e g i v e n t o k e n t h a t c o m e s a f t e r s t a r t P o s
* This by default writes the text provided with the given tokenKind
* but if optional emitFn callback is provided the text is emitted using the callback instead of default text
* @param tokenKind the kind of the token to search and emit
* @param startPos the position in the source to start searching for the token
* @param emitFn if given will be invoked to emit the text instead of actual token emit * /
var emitToken = emitTokenText ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
/ * * C a l l e d t o b e f o r e s t a r t i n g t h e l e x i c a l s c o p e s a s i n f u n c t i o n / c l a s s i n t h e e m i t t e d c o d e b e c a u s e o f n o d e
* @param scopeDeclaration node that starts the lexical scope
* @param scopeName Optional name of this scope instead of deducing one from the declaration node * /
var scopeEmitStart = function ( scopeDeclaration : Node , scopeName? : string ) { }
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
/** Called after coming out of the scope */
var scopeEmitEnd = function ( ) { }
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
/** Sourcemap data that will get encoded */
var sourceMapData : SourceMapData ;
2014-07-17 00:39:14 +02:00
2015-02-05 23:41:04 +01:00
if ( compilerOptions . sourceMap ) {
initializeEmitterWithSourceMaps ( ) ;
}
if ( root ) {
emit ( root ) ;
}
else {
forEach ( host . getSourceFiles ( ) , sourceFile = > {
if ( ! isExternalModuleOrDeclarationFile ( sourceFile ) ) {
emit ( sourceFile ) ;
}
} ) ;
}
writeLine ( ) ;
writeEmittedFiles ( writer . getText ( ) , /*writeByteOrderMark*/ compilerOptions . emitBOM ) ;
return ;
2014-10-11 01:44:14 +02:00
function initializeEmitterWithSourceMaps() {
var sourceMapDir : string ; // The directory in which sourcemap will be
// Current source map file and its index in the sources list
var sourceMapSourceIndex = - 1 ;
// Names and its index map
var sourceMapNameIndexMap : Map < number > = { } ;
var sourceMapNameIndices : number [ ] = [ ] ;
function getSourceMapNameIndex() {
return sourceMapNameIndices . length ? sourceMapNameIndices [ sourceMapNameIndices . length - 1 ] : - 1 ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// Last recorded and encoded spans
var lastRecordedSourceMapSpan : SourceMapSpan ;
var lastEncodedSourceMapSpan : SourceMapSpan = {
emittedLine : 1 ,
emittedColumn : 1 ,
sourceLine : 1 ,
sourceColumn : 1 ,
sourceIndex : 0
} ;
var lastEncodedNameIndex = 0 ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// Encoding for sourcemap span
function encodeLastRecordedSourceMapSpan() {
if ( ! lastRecordedSourceMapSpan || lastRecordedSourceMapSpan === lastEncodedSourceMapSpan ) {
2014-07-17 00:39:14 +02:00
return ;
2014-10-13 06:10:04 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
var prevEncodedEmittedColumn = lastEncodedSourceMapSpan . emittedColumn ;
// Line/Comma delimiters
if ( lastEncodedSourceMapSpan . emittedLine == lastRecordedSourceMapSpan . emittedLine ) {
// Emit comma to separate the entry
if ( sourceMapData . sourceMapMappings ) {
sourceMapData . sourceMapMappings += "," ;
}
2014-10-13 06:10:04 +02:00
}
else {
2014-10-11 01:44:14 +02:00
// Emit line delimiters
for ( var encodedLine = lastEncodedSourceMapSpan . emittedLine ; encodedLine < lastRecordedSourceMapSpan . emittedLine ; encodedLine ++ ) {
sourceMapData . sourceMapMappings += ";" ;
}
prevEncodedEmittedColumn = 1 ;
2014-10-13 06:10:04 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// 1. Relative Column 0 based
sourceMapData . sourceMapMappings += base64VLQFormatEncode ( lastRecordedSourceMapSpan . emittedColumn - prevEncodedEmittedColumn ) ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// 2. Relative sourceIndex
sourceMapData . sourceMapMappings += base64VLQFormatEncode ( lastRecordedSourceMapSpan . sourceIndex - lastEncodedSourceMapSpan . sourceIndex ) ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// 3. Relative sourceLine 0 based
sourceMapData . sourceMapMappings += base64VLQFormatEncode ( lastRecordedSourceMapSpan . sourceLine - lastEncodedSourceMapSpan . sourceLine ) ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// 4. Relative sourceColumn 0 based
sourceMapData . sourceMapMappings += base64VLQFormatEncode ( lastRecordedSourceMapSpan . sourceColumn - lastEncodedSourceMapSpan . sourceColumn ) ;
2014-11-04 02:15:14 +01:00
2014-10-11 01:44:14 +02:00
// 5. Relative namePosition 0 based
if ( lastRecordedSourceMapSpan . nameIndex >= 0 ) {
sourceMapData . sourceMapMappings += base64VLQFormatEncode ( lastRecordedSourceMapSpan . nameIndex - lastEncodedNameIndex ) ;
lastEncodedNameIndex = lastRecordedSourceMapSpan . nameIndex ;
}
2014-11-04 02:15:14 +01:00
2014-10-11 01:44:14 +02:00
lastEncodedSourceMapSpan = lastRecordedSourceMapSpan ;
sourceMapData . sourceMapDecodedMappings . push ( lastEncodedSourceMapSpan ) ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function base64VLQFormatEncode ( inValue : number ) {
function base64FormatEncode ( inValue : number ) {
if ( inValue < 64 ) {
return 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' . charAt ( inValue ) ;
}
throw TypeError ( inValue + ": not a 64 based value" ) ;
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// Add a new least significant bit that has the sign of the value.
// if negative number the least significant bit that gets added to the number has value 1
// else least significant bit value that gets added is 0
// eg. -1 changes to binary : 01 [1] => 3
// +1 changes to binary : 01 [0] => 2
if ( inValue < 0 ) {
inValue = ( ( - inValue ) << 1 ) + 1 ;
2014-11-19 11:11:17 +01:00
}
else {
2014-10-11 01:44:14 +02:00
inValue = inValue << 1 ;
2014-11-19 11:11:17 +01:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// Encode 5 bits at a time starting from least significant bits
var encodedStr = "" ;
do {
var currentDigit = inValue & 31 ; // 11111
inValue = inValue >> 5 ;
if ( inValue > 0 ) {
// There are still more digits to decode, set the msb (6th bit)
currentDigit = currentDigit | 32 ;
}
encodedStr = encodedStr + base64FormatEncode ( currentDigit ) ;
} while ( inValue > 0 ) ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
return encodedStr ;
}
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function recordSourceMapSpan ( pos : number ) {
2015-01-16 21:02:12 +01:00
var sourceLinePos = getLineAndCharacterOfPosition ( currentSourceFile , pos ) ;
2014-10-11 01:44:14 +02:00
var emittedLine = writer . getLine ( ) ;
var emittedColumn = writer . getColumn ( ) ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// If this location wasn't recorded or the location in source is going backwards, record the span
if ( ! lastRecordedSourceMapSpan ||
lastRecordedSourceMapSpan . emittedLine != emittedLine ||
lastRecordedSourceMapSpan . emittedColumn != emittedColumn ||
( lastRecordedSourceMapSpan . sourceIndex === sourceMapSourceIndex &&
2015-02-08 21:15:44 +01:00
( lastRecordedSourceMapSpan . sourceLine > sourceLinePos . line ||
( lastRecordedSourceMapSpan . sourceLine === sourceLinePos . line && lastRecordedSourceMapSpan . sourceColumn > sourceLinePos . character ) ) ) ) {
2014-10-11 01:44:14 +02:00
// Encode the last recordedSpan before assigning new
encodeLastRecordedSourceMapSpan ( ) ;
2014-11-28 19:13:52 +01:00
2014-10-11 01:44:14 +02:00
// New span
lastRecordedSourceMapSpan = {
emittedLine : emittedLine ,
emittedColumn : emittedColumn ,
sourceLine : sourceLinePos.line ,
sourceColumn : sourceLinePos.character ,
nameIndex : getSourceMapNameIndex ( ) ,
sourceIndex : sourceMapSourceIndex
} ;
2014-12-03 00:52:29 +01:00
}
else {
2014-10-11 01:44:14 +02:00
// Take the new pos instead since there is no change in emittedLine and column since last location
lastRecordedSourceMapSpan . sourceLine = sourceLinePos . line ;
lastRecordedSourceMapSpan . sourceColumn = sourceLinePos . character ;
lastRecordedSourceMapSpan . sourceIndex = sourceMapSourceIndex ;
2014-12-03 00:52:29 +01:00
}
2014-11-10 22:05:47 +01:00
}
2014-11-28 19:13:52 +01:00
2014-10-11 01:44:14 +02:00
function recordEmitNodeStartSpan ( node : Node ) {
// Get the token pos after skipping to the token (ignoring the leading trivia)
recordSourceMapSpan ( skipTrivia ( currentSourceFile . text , node . pos ) ) ;
2014-11-28 19:13:52 +01:00
}
2014-10-11 01:44:14 +02:00
function recordEmitNodeEndSpan ( node : Node ) {
recordSourceMapSpan ( node . end ) ;
2014-11-28 19:13:52 +01:00
}
2014-10-11 01:44:14 +02:00
function writeTextWithSpanRecord ( tokenKind : SyntaxKind , startPos : number , emitFn ? : ( ) = > void ) {
var tokenStartPos = ts . skipTrivia ( currentSourceFile . text , startPos ) ;
recordSourceMapSpan ( tokenStartPos ) ;
var tokenEndPos = emitTokenText ( tokenKind , tokenStartPos , emitFn ) ;
recordSourceMapSpan ( tokenEndPos ) ;
return tokenEndPos ;
2014-11-28 19:13:52 +01:00
}
2014-10-11 01:44:14 +02:00
function recordNewSourceFileStart ( node : SourceFile ) {
// Add the file to tsFilePaths
// If sourceroot option: Use the relative path corresponding to the common directory path
// otherwise source locations relative to map file location
2014-12-16 22:52:47 +01:00
var sourcesDirectoryPath = compilerOptions . sourceRoot ? host . getCommonSourceDirectory ( ) : sourceMapDir ;
2014-11-28 19:13:52 +01:00
2014-10-11 01:44:14 +02:00
sourceMapData . sourceMapSources . push ( getRelativePathToDirectoryOrUrl ( sourcesDirectoryPath ,
2015-02-04 01:08:46 +01:00
node . fileName ,
2014-12-16 23:42:58 +01:00
host . getCurrentDirectory ( ) ,
host . getCanonicalFileName ,
2014-10-11 01:44:14 +02:00
/*isAbsolutePathAnUrl*/ true ) ) ;
sourceMapSourceIndex = sourceMapData . sourceMapSources . length - 1 ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// The one that can be used from program to get the actual source file
2015-02-04 01:08:46 +01:00
sourceMapData . inputSourceFileNames . push ( node . fileName ) ;
2014-11-28 19:13:52 +01:00
}
2014-10-11 01:44:14 +02:00
function recordScopeNameOfNode ( node : Node , scopeName? : string ) {
function recordScopeNameIndex ( scopeNameIndex : number ) {
sourceMapNameIndices . push ( scopeNameIndex ) ;
2014-11-28 19:13:52 +01:00
}
2014-10-11 01:44:14 +02:00
function recordScopeNameStart ( scopeName : string ) {
var scopeNameIndex = - 1 ;
if ( scopeName ) {
var parentIndex = getSourceMapNameIndex ( ) ;
if ( parentIndex !== - 1 ) {
2015-01-21 20:01:05 +01:00
// Child scopes are always shown with a dot (even if they have no name),
// unless it is a computed property. Then it is shown with brackets,
// but the brackets are included in the name.
var name = ( < Declaration > node ) . name ;
if ( ! name || name . kind !== SyntaxKind . ComputedPropertyName ) {
scopeName = "." + scopeName ;
}
scopeName = sourceMapData . sourceMapNames [ parentIndex ] + scopeName ;
2014-10-11 01:44:14 +02:00
}
2014-11-28 19:13:52 +01:00
2014-10-11 01:44:14 +02:00
scopeNameIndex = getProperty ( sourceMapNameIndexMap , scopeName ) ;
if ( scopeNameIndex === undefined ) {
scopeNameIndex = sourceMapData . sourceMapNames . length ;
sourceMapData . sourceMapNames . push ( scopeName ) ;
sourceMapNameIndexMap [ scopeName ] = scopeNameIndex ;
}
2014-12-02 20:39:04 +01:00
}
2014-10-11 01:44:14 +02:00
recordScopeNameIndex ( scopeNameIndex ) ;
2014-12-02 20:39:04 +01:00
}
2014-10-11 01:44:14 +02:00
if ( scopeName ) {
// The scope was already given a name use it
recordScopeNameStart ( scopeName ) ;
2014-12-02 20:39:04 +01:00
}
2014-10-11 01:44:14 +02:00
else if ( node . kind === SyntaxKind . FunctionDeclaration ||
node . kind === SyntaxKind . FunctionExpression ||
2014-12-09 01:16:11 +01:00
node . kind === SyntaxKind . MethodDeclaration ||
node . kind === SyntaxKind . MethodSignature ||
2014-10-11 01:44:14 +02:00
node . kind === SyntaxKind . GetAccessor ||
node . kind === SyntaxKind . SetAccessor ||
node . kind === SyntaxKind . ModuleDeclaration ||
node . kind === SyntaxKind . ClassDeclaration ||
node . kind === SyntaxKind . EnumDeclaration ) {
// Declaration and has associated name use it
if ( ( < Declaration > node ) . name ) {
2015-01-21 20:01:05 +01:00
var name = ( < Declaration > node ) . name ;
// For computed property names, the text will include the brackets
scopeName = name . kind === SyntaxKind . ComputedPropertyName
? getTextOfNode ( name )
: ( < Identifier > ( < Declaration > node ) . name ) . text ;
2014-12-02 20:39:04 +01:00
}
2014-10-11 01:44:14 +02:00
recordScopeNameStart ( scopeName ) ;
2014-12-02 20:39:04 +01:00
}
else {
2014-10-11 01:44:14 +02:00
// Block just use the name from upper level scope
recordScopeNameIndex ( getSourceMapNameIndex ( ) ) ;
2014-12-02 20:39:04 +01:00
}
}
2014-10-11 01:44:14 +02:00
function recordScopeNameEnd() {
sourceMapNameIndices . pop ( ) ;
} ;
2014-07-13 01:04:16 +02:00
2014-10-13 19:53:57 +02:00
function writeCommentRangeWithMap ( curentSourceFile : SourceFile , writer : EmitTextWriter , comment : CommentRange , newLine : string ) {
2014-10-11 01:44:14 +02:00
recordSourceMapSpan ( comment . pos ) ;
2014-10-13 19:53:57 +02:00
writeCommentRange ( currentSourceFile , writer , comment , newLine ) ;
2014-10-11 01:44:14 +02:00
recordSourceMapSpan ( comment . end ) ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
function serializeSourceMapContents ( version : number , file : string , sourceRoot : string , sources : string [ ] , names : string [ ] , mappings : string ) {
if ( typeof JSON !== "undefined" ) {
return JSON . stringify ( {
version : version ,
file : file ,
sourceRoot : sourceRoot ,
sources : sources ,
names : names ,
mappings : mappings
} ) ;
2014-12-02 20:39:04 +01:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
return "{\"version\":" + version + ",\"file\":\"" + escapeString ( file ) + "\",\"sourceRoot\":\"" + escapeString ( sourceRoot ) + "\",\"sources\":[" + serializeStringArray ( sources ) + "],\"names\":[" + serializeStringArray ( names ) + "],\"mappings\":\"" + escapeString ( mappings ) + "\"}" ;
2014-08-22 23:40:47 +02:00
2014-10-11 01:44:14 +02:00
function serializeStringArray ( list : string [ ] ) : string {
var output = "" ;
for ( var i = 0 , n = list . length ; i < n ; i ++ ) {
if ( i ) {
output += "," ;
}
output += "\"" + escapeString ( list [ i ] ) + "\"" ;
2014-12-02 20:39:04 +01:00
}
2014-10-11 01:44:14 +02:00
return output ;
2014-12-02 20:39:04 +01:00
}
}
2014-10-11 01:44:14 +02:00
function writeJavaScriptAndSourceMapFile ( emitOutput : string , writeByteOrderMark : boolean ) {
// Write source map file
encodeLastRecordedSourceMapSpan ( ) ;
2014-12-16 23:42:58 +01:00
writeFile ( host , diagnostics , sourceMapData . sourceMapFilePath , serializeSourceMapContents (
2014-10-11 01:44:14 +02:00
3 ,
sourceMapData . sourceMapFile ,
sourceMapData . sourceMapSourceRoot ,
sourceMapData . sourceMapSources ,
sourceMapData . sourceMapNames ,
sourceMapData . sourceMapMappings ) , /*writeByteOrderMark*/ false ) ;
sourceMapDataList . push ( sourceMapData ) ;
2014-11-28 19:13:52 +01:00
2014-10-11 01:44:14 +02:00
// Write sourcemap url to the js file and write the js file
writeJavaScriptFile ( emitOutput + "//# sourceMappingURL=" + sourceMapData . jsSourceMappingURL , writeByteOrderMark ) ;
2014-11-10 22:05:47 +01:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// Initialize source map data
2015-02-04 01:08:46 +01:00
var sourceMapJsFile = getBaseFileName ( normalizeSlashes ( jsFilePath ) ) ;
2014-10-11 01:44:14 +02:00
sourceMapData = {
sourceMapFilePath : jsFilePath + ".map" ,
jsSourceMappingURL : sourceMapJsFile + ".map" ,
sourceMapFile : sourceMapJsFile ,
sourceMapSourceRoot : compilerOptions.sourceRoot || "" ,
sourceMapSources : [ ] ,
inputSourceFileNames : [ ] ,
sourceMapNames : [ ] ,
sourceMapMappings : "" ,
sourceMapDecodedMappings : [ ]
} ;
2014-08-19 21:06:52 +02:00
2014-10-11 01:44:14 +02:00
// Normalize source root and make sure it has trailing "/" so that it can be used to combine paths with the
// relative paths of the sources list in the sourcemap
sourceMapData . sourceMapSourceRoot = ts . normalizeSlashes ( sourceMapData . sourceMapSourceRoot ) ;
if ( sourceMapData . sourceMapSourceRoot . length && sourceMapData . sourceMapSourceRoot . charCodeAt ( sourceMapData . sourceMapSourceRoot . length - 1 ) !== CharacterCodes . slash ) {
sourceMapData . sourceMapSourceRoot += directorySeparator ;
2014-11-10 22:05:47 +01:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
if ( compilerOptions . mapRoot ) {
sourceMapDir = normalizeSlashes ( compilerOptions . mapRoot ) ;
if ( root ) { // emitting single module file
// For modules or multiple emit files the mapRoot will have directory structure like the sources
// So if src\a.ts and src\lib\b.ts are compiled together user would be moving the maps into mapRoot\a.js.map and mapRoot\lib\b.js.map
2014-12-16 22:52:47 +01:00
sourceMapDir = getDirectoryPath ( getSourceFilePathInNewDir ( root , host , sourceMapDir ) ) ;
2014-10-13 06:10:04 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
if ( ! isRootedDiskPath ( sourceMapDir ) && ! isUrl ( sourceMapDir ) ) {
// The relative paths are relative to the common directory
2014-12-16 22:52:47 +01:00
sourceMapDir = combinePaths ( host . getCommonSourceDirectory ( ) , sourceMapDir ) ;
2014-10-11 01:44:14 +02:00
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
2014-12-16 23:42:58 +01:00
host . getCurrentDirectory ( ) ,
host . getCanonicalFileName ,
2014-10-11 01:44:14 +02:00
/*isAbsolutePathAnUrl*/ true ) ;
2014-10-13 06:10:04 +02:00
}
else {
2014-10-11 01:44:14 +02:00
sourceMapData . jsSourceMappingURL = combinePaths ( sourceMapDir , sourceMapData . jsSourceMappingURL ) ;
2014-10-13 06:10:04 +02:00
}
}
2014-10-11 01:44:14 +02:00
else {
sourceMapDir = getDirectoryPath ( normalizePath ( jsFilePath ) ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function emitNodeWithMap ( node : Node ) {
if ( node ) {
if ( node . kind != SyntaxKind . SourceFile ) {
recordEmitNodeStartSpan ( node ) ;
emitNode ( node ) ;
recordEmitNodeEndSpan ( node ) ;
}
else {
recordNewSourceFileStart ( < SourceFile > node ) ;
emitNode ( node ) ;
2014-07-17 00:39:14 +02:00
}
2014-11-23 00:38:20 +01:00
}
}
2014-10-11 01:44:14 +02:00
writeEmittedFiles = writeJavaScriptAndSourceMapFile ;
emit = emitNodeWithMap ;
emitStart = recordEmitNodeStartSpan ;
emitEnd = recordEmitNodeEndSpan ;
emitToken = writeTextWithSpanRecord ;
scopeEmitStart = recordScopeNameOfNode ;
scopeEmitEnd = recordScopeNameEnd ;
writeComment = writeCommentRangeWithMap ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function writeJavaScriptFile ( emitOutput : string , writeByteOrderMark : boolean ) {
2014-12-16 23:42:58 +01:00
writeFile ( host , diagnostics , jsFilePath , emitOutput , writeByteOrderMark ) ;
2014-07-13 01:04:16 +02:00
}
2014-12-05 02:43:15 +01:00
// Create a temporary variable with a unique unused name. The forLoopVariable parameter signals that the
// name should be one that is appropriate for a for loop variable.
function createTempVariable ( location : Node , forLoopVariable? : boolean ) : Identifier {
var name = forLoopVariable ? "_i" : undefined ;
while ( true ) {
if ( name && resolver . isUnknownIdentifier ( location , name ) ) {
break ;
}
// _a .. _h, _j ... _z, _0, _1, ...
2015-02-08 21:13:56 +01:00
name = "_" + ( tempCount < 25 ? String . fromCharCode ( tempCount + ( tempCount < 8 ? 0 : 1 ) + CharacterCodes . a ) : tempCount - 25 ) ;
2014-12-04 01:43:01 +01:00
tempCount ++ ;
2014-07-13 01:04:16 +02:00
}
2014-12-04 01:43:01 +01:00
var result = < Identifier > createNode ( SyntaxKind . Identifier ) ;
result . text = name ;
return result ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
2014-12-04 01:43:01 +01:00
function recordTempDeclaration ( name : Identifier ) {
if ( ! tempVariables ) {
tempVariables = [ ] ;
}
tempVariables . push ( name ) ;
2014-07-13 01:04:16 +02:00
}
2014-12-04 01:43:01 +01:00
function emitTempDeclarations ( newLine : boolean ) {
if ( tempVariables ) {
if ( newLine ) {
writeLine ( ) ;
}
else {
write ( " " ) ;
}
write ( "var " ) ;
emitCommaList ( tempVariables ) ;
write ( ";" ) ;
2014-08-22 23:40:47 +02:00
}
2014-12-04 01:43:01 +01:00
}
2014-08-22 23:40:47 +02:00
2014-10-11 01:44:14 +02:00
function emitTokenText ( tokenKind : SyntaxKind , startPos : number , emitFn ? : ( ) = > void ) {
var tokenString = tokenToString ( tokenKind ) ;
if ( emitFn ) {
emitFn ( ) ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
else {
2014-10-11 01:44:14 +02:00
write ( tokenString ) ;
2014-08-14 15:21:30 +02:00
}
2014-10-11 01:44:14 +02:00
return startPos + tokenString . length ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function emitOptional ( prefix : string , node : Node ) {
if ( node ) {
write ( prefix ) ;
emit ( node ) ;
2014-07-13 01:04:16 +02:00
}
}
2014-12-12 01:23:57 +01:00
function emitParenthesized ( node : Node , parenthesized : boolean ) {
if ( parenthesized ) {
write ( "(" ) ;
}
emit ( node ) ;
if ( parenthesized ) {
write ( ")" ) ;
}
}
2014-12-04 01:43:01 +01:00
function emitTrailingCommaIfPresent ( nodeList : NodeArray < Node > ) : void {
2014-10-11 01:44:14 +02:00
if ( nodeList . hasTrailingComma ) {
write ( "," ) ;
2014-07-18 04:54:21 +02:00
}
}
2014-12-12 01:23:57 +01:00
function emitList ( nodes : Node [ ] , start : number , count : number , multiLine : boolean , trailingComma : boolean ) {
if ( multiLine ) {
increaseIndent ( ) ;
2014-07-17 00:39:14 +02:00
}
2014-12-12 01:23:57 +01:00
for ( var i = 0 ; i < count ; i ++ ) {
if ( multiLine ) {
if ( i ) {
write ( "," ) ;
}
writeLine ( ) ;
}
else {
2014-10-11 01:44:14 +02:00
if ( i ) {
write ( ", " ) ;
2014-08-22 23:40:47 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-12-12 01:23:57 +01:00
emit ( nodes [ start + i ] ) ;
}
if ( trailingComma ) {
write ( "," ) ;
}
if ( multiLine ) {
decreaseIndent ( ) ;
writeLine ( ) ;
}
}
function emitCommaList ( nodes : Node [ ] ) {
if ( nodes ) {
emitList ( nodes , 0 , nodes . length , /*multiline*/ false , /*trailingComma*/ false ) ;
2014-07-17 00:39:14 +02:00
}
}
2014-12-04 01:43:01 +01:00
function emitMultiLineList ( nodes : Node [ ] ) {
2014-10-11 01:44:14 +02:00
if ( nodes ) {
2014-12-12 01:23:57 +01:00
emitList ( nodes , 0 , nodes . length , /*multiline*/ true , /*trailingComma*/ false ) ;
2014-07-17 00:39:14 +02:00
}
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitLines ( nodes : Node [ ] ) {
emitLinesStartingAt ( nodes , /*startIndex*/ 0 ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
function emitLinesStartingAt ( nodes : Node [ ] , startIndex : number ) : void {
for ( var i = startIndex ; i < nodes . length ; i ++ ) {
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emit ( nodes [ i ] ) ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-12-01 20:22:37 +01:00
function isBinaryOrOctalIntegerLiteral ( text : string ) : boolean {
if ( text . length <= 0 ) {
return false ;
2014-07-17 00:39:14 +02:00
}
2014-12-01 20:22:37 +01:00
if ( text . charCodeAt ( 1 ) === CharacterCodes . B || text . charCodeAt ( 1 ) === CharacterCodes . b ||
text . charCodeAt ( 1 ) === CharacterCodes . O || text . charCodeAt ( 1 ) === CharacterCodes . o ) {
return true ;
}
return false ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
function emitLiteral ( node : LiteralExpression ) {
2015-01-16 16:15:31 +01:00
var text = languageVersion < ScriptTarget . ES6 && isTemplateLiteralKind ( node . kind ) ? getTemplateLiteralAsStringLiteral ( node ) :
2014-12-04 01:43:01 +01:00
node . parent ? getSourceTextOfNodeFromSourceFile ( currentSourceFile , node ) :
2015-02-08 21:15:44 +01:00
node . text ;
2014-11-21 05:24:08 +01:00
if ( compilerOptions . sourceMap && ( node . kind === SyntaxKind . StringLiteral || isTemplateLiteralKind ( node . kind ) ) ) {
2014-10-11 01:44:14 +02:00
writer . writeLiteral ( text ) ;
2014-07-17 00:39:14 +02:00
}
2014-12-01 20:22:37 +01:00
// For version below ES6, emit binary integer literal and octal integer literal in canonical form
2015-01-16 16:15:31 +01:00
else if ( languageVersion < ScriptTarget . ES6 && node . kind === SyntaxKind . NumericLiteral && isBinaryOrOctalIntegerLiteral ( text ) ) {
2014-12-01 20:22:37 +01:00
write ( node . text ) ;
2014-07-17 00:39:14 +02:00
}
else {
2014-10-11 01:44:14 +02:00
write ( text ) ;
2014-07-17 00:39:14 +02:00
}
}
2014-11-21 05:24:08 +01:00
function getTemplateLiteralAsStringLiteral ( node : LiteralExpression ) : string {
return '"' + escapeString ( node . text ) + '"' ;
2014-07-17 00:39:14 +02:00
}
2014-11-21 05:24:08 +01:00
function emitTemplateExpression ( node : TemplateExpression ) : void {
// In ES6 mode and above, we can simply emit each portion of a template in order, but in
// ES3 & ES5 we must convert the template expression into a series of string concatenations.
2015-01-16 16:15:31 +01:00
if ( languageVersion >= ScriptTarget . ES6 ) {
2014-11-21 05:24:08 +01:00
forEachChild ( node , emit ) ;
2014-10-28 07:56:07 +01:00
return ;
}
2014-08-22 23:40:47 +02:00
2014-11-21 05:24:08 +01:00
var emitOuterParens = isExpression ( node . parent )
&& templateNeedsParens ( node , < Expression > node . parent ) ;
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
if ( emitOuterParens ) {
write ( "(" ) ;
2014-08-14 15:42:18 +02:00
}
2014-08-15 00:41:57 +02:00
2015-01-07 00:28:06 +01:00
var headEmitted = false ;
if ( shouldEmitTemplateHead ( ) ) {
emitLiteral ( node . head ) ;
headEmitted = true ;
}
for ( var i = 0 ; i < node . templateSpans . length ; i ++ ) {
var templateSpan = node . templateSpans [ i ] ;
2014-08-22 23:40:47 +02:00
2014-11-21 05:24:08 +01:00
// Check if the expression has operands and binds its operands less closely than binary '+'.
// If it does, we need to wrap the expression in parentheses. Otherwise, something like
// `abc${ 1 << 2 }`
// becomes
// "abc" + 1 << 2 + ""
// which is really
// ("abc" + 1) << (2 + "")
// rather than
// "abc" + (1 << 2) + ""
2014-11-30 00:58:55 +01:00
var needsParens = templateSpan . expression . kind !== SyntaxKind . ParenthesizedExpression
2014-11-21 05:24:08 +01:00
&& comparePrecedenceToBinaryPlus ( templateSpan . expression ) !== Comparison . GreaterThan ;
2015-01-07 00:28:06 +01:00
if ( i > 0 || headEmitted ) {
// If this is the first span and the head was not emitted, then this templateSpan's
// expression will be the first to be emitted. Don't emit the preceding ' + ' in that
// case.
write ( " + " ) ;
}
2014-12-12 01:23:57 +01:00
emitParenthesized ( templateSpan . expression , needsParens ) ;
2014-11-21 05:24:08 +01:00
// Only emit if the literal is non-empty.
// The binary '+' operator is left-associative, so the first string concatenation
// with the head will force the result up to this point to be a string.
// Emitting a '+ ""' has no semantic effect for middles and tails.
if ( templateSpan . literal . text . length !== 0 ) {
write ( " + " )
emitLiteral ( templateSpan . literal ) ;
2014-08-15 00:41:57 +02:00
}
2015-01-07 00:28:06 +01:00
}
2014-07-13 01:04:16 +02:00
2014-11-21 05:24:08 +01:00
if ( emitOuterParens ) {
write ( ")" ) ;
}
2014-07-13 01:04:16 +02:00
2015-01-07 00:28:06 +01:00
function shouldEmitTemplateHead() {
// If this expression has an empty head literal and the first template span has a non-empty
// literal, then emitting the empty head literal is not necessary.
// `${ foo } and ${ bar }`
// can be emitted as
// foo + " and " + bar
// This is because it is only required that one of the first two operands in the emit
// output must be a string literal, so that the other operand and all following operands
// are forced into strings.
//
// If the first template span has an empty literal, then the head must still be emitted.
// `${ foo }${ bar }`
// must still be emitted as
// "" + foo + bar
// There is always atleast one templateSpan in this code path, since
// NoSubstitutionTemplateLiterals are directly emitted via emitLiteral()
Debug . assert ( node . templateSpans . length !== 0 ) ;
return node . head . text . length !== 0 || node . templateSpans [ 0 ] . literal . text . length === 0 ;
}
2014-11-21 05:24:08 +01:00
function templateNeedsParens ( template : TemplateExpression , parent : Expression ) {
switch ( parent . kind ) {
case SyntaxKind . CallExpression :
case SyntaxKind . NewExpression :
2014-11-30 00:47:02 +01:00
return ( < CallExpression > parent ) . expression === template ;
2015-02-03 00:14:19 +01:00
case SyntaxKind . TaggedTemplateExpression :
2014-11-30 00:58:55 +01:00
case SyntaxKind . ParenthesizedExpression :
2014-11-21 05:24:08 +01:00
return false ;
default :
return comparePrecedenceToBinaryPlus ( parent ) !== Comparison . LessThan ;
2014-08-22 02:17:32 +02:00
}
2014-11-12 20:45:43 +01:00
}
2014-11-21 05:24:08 +01:00
/ * *
* Returns whether the expression has lesser , greater ,
* or equal precedence to the binary '+' operator
* /
function comparePrecedenceToBinaryPlus ( expression : Expression ) : Comparison {
2015-01-06 11:42:02 +01:00
// All binary expressions have lower precedence than '+' apart from '*', '/', and '%'
// which have greater precedence and '-' which has equal precedence.
2014-11-21 05:24:08 +01:00
// All unary operators have a higher precedence apart from yield.
// Arrow functions and conditionals have a lower precedence,
// although we convert the former into regular function expressions in ES5 mode,
// and in ES6 mode this function won't get called anyway.
//
// TODO (drosen): Note that we need to account for the upcoming 'yield' and
// spread ('...') unary operators that are anticipated for ES6.
switch ( expression . kind ) {
case SyntaxKind . BinaryExpression :
switch ( ( < BinaryExpression > expression ) . operator ) {
case SyntaxKind . AsteriskToken :
case SyntaxKind . SlashToken :
case SyntaxKind . PercentToken :
return Comparison . GreaterThan ;
case SyntaxKind . PlusToken :
2015-01-06 11:42:02 +01:00
case SyntaxKind . MinusToken :
2014-11-21 05:24:08 +01:00
return Comparison . EqualTo ;
default :
return Comparison . LessThan ;
}
case SyntaxKind . ConditionalExpression :
return Comparison . LessThan ;
default :
return Comparison . GreaterThan ;
2014-08-15 00:41:57 +02:00
}
}
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
function emitTemplateSpan ( span : TemplateSpan ) {
emit ( span . expression ) ;
emit ( span . literal ) ;
2014-08-22 23:17:52 +02:00
}
2014-10-11 01:44:14 +02:00
// This function specifically handles numeric/string literals for enum and accessor 'identifiers'.
// In a sense, it does not actually emit identifiers as much as it declares a name for a specific property.
2014-11-21 05:24:08 +01:00
function emitExpressionForPropertyName ( node : DeclarationName ) {
2014-10-11 01:44:14 +02:00
if ( node . kind === SyntaxKind . StringLiteral ) {
2014-11-21 05:24:08 +01:00
emitLiteral ( < LiteralExpression > node ) ;
2014-07-17 00:39:14 +02:00
}
2014-11-18 00:53:03 +01:00
else if ( node . kind === SyntaxKind . ComputedPropertyName ) {
emit ( ( < ComputedPropertyName > node ) . expression ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else {
write ( "\"" ) ;
2014-08-15 00:41:57 +02:00
2014-10-11 01:44:14 +02:00
if ( node . kind === SyntaxKind . NumericLiteral ) {
2014-11-21 05:24:08 +01:00
write ( ( < LiteralExpression > node ) . text ) ;
2014-07-18 02:43:48 +02:00
}
else {
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node ) ;
2014-07-18 02:43:48 +02:00
}
2014-10-11 01:44:14 +02:00
write ( "\"" ) ;
2014-08-15 00:41:57 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
function isNotExpressionIdentifier ( node : Identifier ) {
2014-10-11 01:44:14 +02:00
var parent = node . parent ;
switch ( parent . kind ) {
case SyntaxKind . Parameter :
case SyntaxKind . VariableDeclaration :
2014-12-06 22:53:06 +01:00
case SyntaxKind . BindingElement :
2014-12-09 01:37:35 +01:00
case SyntaxKind . PropertyDeclaration :
case SyntaxKind . PropertySignature :
2014-10-11 01:44:14 +02:00
case SyntaxKind . PropertyAssignment :
2014-11-21 05:24:08 +01:00
case SyntaxKind . ShorthandPropertyAssignment :
2014-10-11 01:44:14 +02:00
case SyntaxKind . EnumMember :
2014-12-09 01:16:11 +01:00
case SyntaxKind . MethodDeclaration :
case SyntaxKind . MethodSignature :
2014-10-11 01:44:14 +02:00
case SyntaxKind . FunctionDeclaration :
case SyntaxKind . GetAccessor :
case SyntaxKind . SetAccessor :
case SyntaxKind . FunctionExpression :
case SyntaxKind . ClassDeclaration :
case SyntaxKind . InterfaceDeclaration :
case SyntaxKind . EnumDeclaration :
case SyntaxKind . ModuleDeclaration :
2015-01-27 23:42:20 +01:00
case SyntaxKind . ImportEqualsDeclaration :
2014-10-11 01:44:14 +02:00
return ( < Declaration > parent ) . name === node ;
case SyntaxKind . BreakStatement :
case SyntaxKind . ContinueStatement :
case SyntaxKind . ExportAssignment :
return false ;
case SyntaxKind . LabeledStatement :
return ( < LabeledStatement > node . parent ) . label === node ;
2014-12-02 08:17:34 +01:00
case SyntaxKind . CatchClause :
return ( < CatchClause > node . parent ) . name === node ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
function emitExpressionIdentifier ( node : Identifier ) {
var prefix = resolver . getExpressionNamePrefix ( node ) ;
if ( prefix ) {
write ( prefix ) ;
write ( "." ) ;
2014-08-22 23:50:56 +02:00
}
2014-11-21 05:24:08 +01:00
writeTextOfNode ( currentSourceFile , node ) ;
}
2014-10-11 01:44:14 +02:00
function emitIdentifier ( node : Identifier ) {
2014-12-04 01:43:01 +01:00
if ( ! node . parent ) {
write ( node . text ) ;
2014-07-13 01:04:16 +02:00
}
2014-12-04 01:43:01 +01:00
else if ( ! isNotExpressionIdentifier ( node ) ) {
2014-11-21 05:24:08 +01:00
emitExpressionIdentifier ( node ) ;
2014-07-17 00:39:14 +02:00
}
2014-11-21 05:24:08 +01:00
else {
writeTextOfNode ( currentSourceFile , node ) ;
2014-09-07 02:40:19 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function emitThis ( node : Node ) {
if ( resolver . getNodeCheckFlags ( node ) & NodeCheckFlags . LexicalThis ) {
write ( "_this" ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
else {
write ( "this" ) ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitSuper ( node : Node ) {
var flags = resolver . getNodeCheckFlags ( node ) ;
if ( flags & NodeCheckFlags . SuperInstance ) {
write ( "_super.prototype" ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else if ( flags & NodeCheckFlags . SuperStatic ) {
write ( "_super" ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else {
write ( "super" ) ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-12-04 01:43:01 +01:00
function emitObjectBindingPattern ( node : BindingPattern ) {
write ( "{ " ) ;
2014-12-12 01:23:57 +01:00
var elements = node . elements ;
emitList ( elements , 0 , elements . length , /*multiLine*/ false , /*trailingComma*/ elements . hasTrailingComma ) ;
2014-12-04 01:43:01 +01:00
write ( " }" ) ;
2014-07-13 01:04:16 +02:00
}
2014-12-04 01:43:01 +01:00
function emitArrayBindingPattern ( node : BindingPattern ) {
write ( "[" ) ;
2014-12-12 01:23:57 +01:00
var elements = node . elements ;
emitList ( elements , 0 , elements . length , /*multiLine*/ false , /*trailingComma*/ elements . hasTrailingComma ) ;
2014-12-04 01:43:01 +01:00
write ( "]" ) ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
2014-12-14 18:43:14 +01:00
function emitBindingElement ( node : BindingElement ) {
if ( node . propertyName ) {
emit ( node . propertyName ) ;
write ( ": " ) ;
}
if ( node . dotDotDotToken ) {
write ( "..." ) ;
}
if ( isBindingPattern ( node . name ) ) {
emit ( node . name ) ;
2014-10-11 01:44:14 +02:00
}
else {
2014-12-14 18:43:14 +01:00
emitModuleMemberName ( node ) ;
}
emitOptional ( " = " , node . initializer ) ;
}
2014-12-12 01:23:57 +01:00
function emitSpreadElementExpression ( node : SpreadElementExpression ) {
write ( "..." ) ;
emit ( ( < SpreadElementExpression > node ) . expression ) ;
}
function needsParenthesisForPropertyAccess ( node : Expression ) {
switch ( node . kind ) {
case SyntaxKind . Identifier :
case SyntaxKind . ArrayLiteralExpression :
case SyntaxKind . PropertyAccessExpression :
case SyntaxKind . ElementAccessExpression :
case SyntaxKind . CallExpression :
case SyntaxKind . ParenthesizedExpression :
2014-12-17 00:47:22 +01:00
// This list is not exhaustive and only includes those cases that are relevant
// to the check in emitArrayLiteral. More cases can be added as needed.
2014-12-12 01:23:57 +01:00
return false ;
}
return true ;
}
2014-11-30 00:58:55 +01:00
function emitArrayLiteral ( node : ArrayLiteralExpression ) {
2014-12-12 01:23:57 +01:00
var elements = node . elements ;
var length = elements . length ;
if ( length === 0 ) {
write ( "[]" ) ;
return ;
2014-10-11 01:44:14 +02:00
}
2015-01-16 16:15:31 +01:00
if ( languageVersion >= ScriptTarget . ES6 ) {
2014-10-11 01:44:14 +02:00
write ( "[" ) ;
2014-12-12 01:23:57 +01:00
emitList ( elements , 0 , elements . length , /*multiLine*/ ( node . flags & NodeFlags . MultiLine ) !== 0 ,
/*trailingComma*/ elements . hasTrailingComma ) ;
2014-10-11 01:44:14 +02:00
write ( "]" ) ;
2014-12-12 01:23:57 +01:00
return ;
}
var pos = 0 ;
var group = 0 ;
while ( pos < length ) {
2014-12-16 00:16:54 +01:00
// Emit using the pattern <group0>.concat(<group1>, <group2>, ...)
2014-12-12 01:23:57 +01:00
if ( group === 1 ) {
write ( ".concat(" ) ;
}
else if ( group > 1 ) {
write ( ", " ) ;
}
var e = elements [ pos ] ;
if ( e . kind === SyntaxKind . SpreadElementExpression ) {
e = ( < SpreadElementExpression > e ) . expression ;
emitParenthesized ( e , /*parenthesized*/ group === 0 && needsParenthesisForPropertyAccess ( e ) ) ;
pos ++ ;
}
else {
2014-12-16 00:16:54 +01:00
var i = pos ;
while ( i < length && elements [ i ] . kind !== SyntaxKind . SpreadElementExpression ) {
i ++ ;
}
2014-12-12 01:23:57 +01:00
write ( "[" ) ;
2015-02-08 21:15:44 +01:00
emitList ( elements , pos , i - pos , /*multiLine*/ ( node . flags & NodeFlags . MultiLine ) !== 0 ,
2014-12-12 01:23:57 +01:00
/*trailingComma*/ elements . hasTrailingComma ) ;
write ( "]" ) ;
pos = i ;
}
group ++ ;
}
if ( group > 1 ) {
write ( ")" ) ;
2014-07-17 00:39:14 +02:00
}
}
2014-11-30 00:58:55 +01:00
function emitObjectLiteral ( node : ObjectLiteralExpression ) {
2014-12-12 01:23:57 +01:00
write ( "{" ) ;
var properties = node . properties ;
if ( properties . length ) {
var multiLine = ( node . flags & NodeFlags . MultiLine ) !== 0 ;
if ( ! multiLine ) {
write ( " " ) ;
2014-07-18 02:43:48 +02:00
}
2014-12-12 01:23:57 +01:00
emitList ( properties , 0 , properties . length , /*multiLine*/ multiLine ,
2015-01-16 16:15:31 +01:00
/*trailingComma*/ properties . hasTrailingComma && languageVersion >= ScriptTarget . ES5 ) ;
2014-12-12 01:23:57 +01:00
if ( ! multiLine ) {
write ( " " ) ;
2014-07-18 02:43:48 +02:00
}
}
2014-12-12 01:23:57 +01:00
write ( "}" ) ;
2014-07-19 01:59:52 +02:00
}
2014-11-18 00:53:03 +01:00
function emitComputedPropertyName ( node : ComputedPropertyName ) {
write ( "[" ) ;
emit ( node . expression ) ;
write ( "]" ) ;
}
2014-12-03 09:04:54 +01:00
2014-12-03 11:09:15 +01:00
function emitMethod ( node : MethodDeclaration ) {
2014-10-11 01:44:14 +02:00
emit ( node . name ) ;
2015-01-16 16:15:31 +01:00
if ( languageVersion < ScriptTarget . ES6 ) {
2014-12-08 23:34:00 +01:00
write ( ": function " ) ;
}
2014-12-03 11:09:15 +01:00
emitSignatureAndBody ( node ) ;
2014-10-11 01:44:14 +02:00
}
2014-08-15 00:41:57 +02:00
2014-10-11 01:44:14 +02:00
function emitPropertyAssignment ( node : PropertyDeclaration ) {
2014-11-25 21:12:55 +01:00
emit ( node . name ) ;
write ( ": " ) ;
2014-10-11 01:44:14 +02:00
emit ( node . initializer ) ;
2014-11-25 21:12:55 +01:00
}
2014-12-08 23:34:00 +01:00
function emitShorthandPropertyAssignment ( node : ShorthandPropertyAssignment ) {
2014-11-25 21:12:55 +01:00
emit ( node . name ) ;
2014-12-02 22:29:49 +01:00
// If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example:
// module m {
// export var y;
// }
// module m {
// export var obj = { y };
// }
// The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version
2015-01-16 16:15:31 +01:00
if ( languageVersion < ScriptTarget . ES6 || resolver . getExpressionNamePrefix ( node . name ) ) {
2014-12-08 23:34:00 +01:00
// Emit identifier as an identifier
write ( ": " ) ;
// Even though this is stored as identifier treat it as an expression
// Short-hand, { x }, is equivalent of normal form { x: x }
emitExpressionIdentifier ( node . name ) ;
2014-11-21 05:24:08 +01:00
}
}
2014-11-30 00:58:55 +01:00
function tryEmitConstantValue ( node : PropertyAccessExpression | ElementAccessExpression ) : boolean {
2014-10-11 01:44:14 +02:00
var constantValue = resolver . getConstantValue ( node ) ;
if ( constantValue !== undefined ) {
2015-01-30 12:09:31 +01:00
write ( constantValue . toString ( ) ) ;
if ( ! compilerOptions . removeComments ) {
var propertyName : string = node . kind === SyntaxKind . PropertyAccessExpression ? declarationNameToString ( ( < PropertyAccessExpression > node ) . name ) : getTextOfNode ( ( < ElementAccessExpression > node ) . argumentExpression ) ;
write ( " /* " + propertyName + " */" ) ;
}
2014-11-21 05:24:08 +01:00
return true ;
2014-07-17 00:39:14 +02:00
}
2014-11-21 05:24:08 +01:00
return false ;
2014-07-17 00:39:14 +02:00
}
2014-11-30 00:58:55 +01:00
function emitPropertyAccess ( node : PropertyAccessExpression ) {
2014-11-21 05:24:08 +01:00
if ( tryEmitConstantValue ( node ) ) {
2014-08-22 23:35:07 +02:00
return ;
}
2014-11-30 02:25:52 +01:00
emit ( node . expression ) ;
2014-11-21 05:24:08 +01:00
write ( "." ) ;
2014-11-30 02:25:52 +01:00
emit ( node . name ) ;
2014-07-13 01:04:16 +02:00
}
2014-08-22 23:35:07 +02:00
2014-11-30 01:48:28 +01:00
function emitQualifiedName ( node : QualifiedName ) {
2014-11-21 05:24:08 +01:00
emit ( node . left ) ;
write ( "." ) ;
emit ( node . right ) ;
2014-07-13 01:04:16 +02:00
}
2014-08-22 23:35:07 +02:00
2014-11-30 00:47:02 +01:00
function emitIndexedAccess ( node : ElementAccessExpression ) {
2014-11-21 05:24:08 +01:00
if ( tryEmitConstantValue ( node ) ) {
return ;
2014-08-22 23:35:07 +02:00
}
2014-11-30 00:47:02 +01:00
emit ( node . expression ) ;
2014-10-11 01:44:14 +02:00
write ( "[" ) ;
2014-11-30 00:47:02 +01:00
emit ( node . argumentExpression ) ;
2014-10-11 01:44:14 +02:00
write ( "]" ) ;
2014-07-13 01:04:16 +02:00
}
2014-08-22 23:35:07 +02:00
2014-10-11 01:44:14 +02:00
function emitCallExpression ( node : CallExpression ) {
var superCall = false ;
2014-11-30 00:47:02 +01:00
if ( node . expression . kind === SyntaxKind . SuperKeyword ) {
2014-10-11 01:44:14 +02:00
write ( "_super" ) ;
superCall = true ;
2014-08-22 23:50:56 +02:00
}
2014-10-11 01:44:14 +02:00
else {
2014-11-30 00:47:02 +01:00
emit ( node . expression ) ;
2014-11-30 02:25:52 +01:00
superCall = node . expression . kind === SyntaxKind . PropertyAccessExpression && ( < PropertyAccessExpression > node . expression ) . expression . kind === SyntaxKind . SuperKeyword ;
2014-10-11 01:44:14 +02:00
}
if ( superCall ) {
write ( ".call(" ) ;
2014-11-30 00:47:02 +01:00
emitThis ( node . expression ) ;
2014-10-11 01:44:14 +02:00
if ( node . arguments . length ) {
write ( ", " ) ;
2014-12-04 01:43:01 +01:00
emitCommaList ( node . arguments ) ;
2014-10-11 01:44:14 +02:00
}
write ( ")" ) ;
2014-07-13 01:04:16 +02:00
}
else {
2014-10-11 01:44:14 +02:00
write ( "(" ) ;
2014-12-04 01:43:01 +01:00
emitCommaList ( node . arguments ) ;
2014-10-11 01:44:14 +02:00
write ( ")" ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
}
function emitNewExpression ( node : NewExpression ) {
write ( "new " ) ;
2014-11-30 00:47:02 +01:00
emit ( node . expression ) ;
2014-10-11 01:44:14 +02:00
if ( node . arguments ) {
write ( "(" ) ;
2014-12-04 01:43:01 +01:00
emitCommaList ( node . arguments ) ;
2014-10-11 01:44:14 +02:00
write ( ")" ) ;
2014-09-07 02:40:19 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
function emitTaggedTemplateExpression ( node : TaggedTemplateExpression ) : void {
emit ( node . tag ) ;
write ( " " ) ;
emit ( node . template ) ;
}
2014-11-30 00:58:55 +01:00
function emitParenExpression ( node : ParenthesizedExpression ) {
if ( node . expression . kind === SyntaxKind . TypeAssertionExpression ) {
2014-11-30 00:47:02 +01:00
var operand = ( < TypeAssertion > node . expression ) . expression ;
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
// Make sure we consider all nested cast expressions, e.g.:
// (<any><number><any>-A).x;
2014-11-30 00:58:55 +01:00
while ( operand . kind == SyntaxKind . TypeAssertionExpression ) {
2014-11-30 00:47:02 +01:00
operand = ( < TypeAssertion > operand ) . expression ;
2014-10-11 01:44:14 +02:00
}
// We have an expression of the form: (<Type>SubExpr)
// Emitting this as (SubExpr) is really not desirable. We would like to emit the subexpr as is.
// Omitting the parentheses, however, could cause change in the semantics of the generated
// code if the casted expression has a lower precedence than the rest of the expression, e.g.:
// (<any>new A).foo should be emitted as (new A).foo and not new A.foo
// (<any>typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString()
// new (<any>A()) should be emitted as new (A()) and not new A()
// (<any>function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} ()
2014-11-29 22:43:30 +01:00
if ( operand . kind !== SyntaxKind . PrefixUnaryExpression &&
operand . kind !== SyntaxKind . VoidExpression &&
operand . kind !== SyntaxKind . TypeOfExpression &&
operand . kind !== SyntaxKind . DeleteExpression &&
2014-11-30 00:58:55 +01:00
operand . kind !== SyntaxKind . PostfixUnaryExpression &&
2014-11-29 22:43:30 +01:00
operand . kind !== SyntaxKind . NewExpression &&
2014-10-11 01:44:14 +02:00
! ( operand . kind === SyntaxKind . CallExpression && node . parent . kind === SyntaxKind . NewExpression ) &&
! ( operand . kind === SyntaxKind . FunctionExpression && node . parent . kind === SyntaxKind . CallExpression ) ) {
emit ( operand ) ;
2014-07-17 00:39:14 +02:00
return ;
2014-10-11 01:44:14 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
write ( "(" ) ;
emit ( node . expression ) ;
write ( ")" ) ;
}
2014-07-13 01:04:16 +02:00
2014-11-29 22:43:30 +01:00
function emitDeleteExpression ( node : DeleteExpression ) {
write ( tokenToString ( SyntaxKind . DeleteKeyword ) ) ;
write ( " " ) ;
emit ( node . expression ) ;
}
function emitVoidExpression ( node : VoidExpression ) {
write ( tokenToString ( SyntaxKind . VoidKeyword ) ) ;
write ( " " ) ;
emit ( node . expression ) ;
}
function emitTypeOfExpression ( node : TypeOfExpression ) {
write ( tokenToString ( SyntaxKind . TypeOfKeyword ) ) ;
write ( " " ) ;
emit ( node . expression ) ;
}
2014-11-30 01:48:28 +01:00
function emitPrefixUnaryExpression ( node : PrefixUnaryExpression ) {
write ( tokenToString ( node . operator ) ) ;
2014-10-11 01:44:14 +02:00
// In some cases, we need to emit a space between the operator and the operand. One obvious case
// is when the operator is an identifier, like delete or typeof. We also need to do this for plus
// and minus expressions in certain cases. Specifically, consider the following two cases (parens
// are just for clarity of exposition, and not part of the source code):
//
// (+(+1))
// (+(++1))
//
// We need to emit a space in both cases. In the first case, the absence of a space will make
// the resulting expression a prefix increment operation. And in the second, it will make the resulting
// expression a prefix increment whose operand is a plus expression - (++(+x))
// The same is true of minus of course.
2014-12-01 06:22:23 +01:00
if ( node . operand . kind === SyntaxKind . PrefixUnaryExpression ) {
2014-11-30 01:48:28 +01:00
var operand = < PrefixUnaryExpression > node . operand ;
2014-10-11 01:44:14 +02:00
if ( node . operator === SyntaxKind . PlusToken && ( operand . operator === SyntaxKind . PlusToken || operand . operator === SyntaxKind . PlusPlusToken ) ) {
write ( " " ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else if ( node . operator === SyntaxKind . MinusToken && ( operand . operator === SyntaxKind . MinusToken || operand . operator === SyntaxKind . MinusMinusToken ) ) {
write ( " " ) ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
emit ( node . operand ) ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-11-30 01:48:28 +01:00
function emitPostfixUnaryExpression ( node : PostfixUnaryExpression ) {
emit ( node . operand ) ;
write ( tokenToString ( node . operator ) ) ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitBinaryExpression ( node : BinaryExpression ) {
2015-01-16 16:15:31 +01:00
if ( languageVersion < ScriptTarget . ES6 && node . operator === SyntaxKind . EqualsToken &&
2014-12-14 18:43:14 +01:00
( node . left . kind === SyntaxKind . ObjectLiteralExpression || node . left . kind === SyntaxKind . ArrayLiteralExpression ) ) {
2014-12-04 01:43:01 +01:00
emitDestructuring ( node ) ;
}
else {
emit ( node . left ) ;
if ( node . operator !== SyntaxKind . CommaToken ) write ( " " ) ;
write ( tokenToString ( node . operator ) ) ;
write ( " " ) ;
emit ( node . right ) ;
}
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function emitConditionalExpression ( node : ConditionalExpression ) {
emit ( node . condition ) ;
write ( " ? " ) ;
emit ( node . whenTrue ) ;
write ( " : " ) ;
emit ( node . whenFalse ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
function emitBlock ( node : Block ) {
emitToken ( SyntaxKind . OpenBraceToken , node . pos ) ;
2014-07-13 01:04:16 +02:00
increaseIndent ( ) ;
2014-10-11 01:44:14 +02:00
scopeEmitStart ( node . parent ) ;
if ( node . kind === SyntaxKind . ModuleBlock ) {
Debug . assert ( node . parent . kind === SyntaxKind . ModuleDeclaration ) ;
emitCaptureThisForNodeIfNecessary ( node . parent ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
emitLines ( node . statements ) ;
2014-12-04 01:43:01 +01:00
if ( node . kind === SyntaxKind . ModuleBlock ) {
emitTempDeclarations ( /*newLine*/ true ) ;
}
2014-07-13 01:04:16 +02:00
decreaseIndent ( ) ;
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emitToken ( SyntaxKind . CloseBraceToken , node . statements . end ) ;
scopeEmitEnd ( ) ;
2014-08-22 02:17:02 +02:00
}
2014-10-11 01:44:14 +02:00
function emitEmbeddedStatement ( node : Node ) {
if ( node . kind === SyntaxKind . Block ) {
write ( " " ) ;
emit ( < Block > node ) ;
2014-08-22 02:17:02 +02:00
}
else {
2014-10-11 01:44:14 +02:00
increaseIndent ( ) ;
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emit ( node ) ;
decreaseIndent ( ) ;
2014-08-22 02:17:02 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-08-22 02:17:02 +02:00
2014-10-11 01:44:14 +02:00
function emitExpressionStatement ( node : ExpressionStatement ) {
2014-12-12 01:23:57 +01:00
emitParenthesized ( node . expression , /*parenthesized*/ node . expression . kind === SyntaxKind . ArrowFunction ) ;
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
2014-08-22 02:17:02 +02:00
}
2014-10-11 01:44:14 +02:00
function emitIfStatement ( node : IfStatement ) {
var endPos = emitToken ( SyntaxKind . IfKeyword , node . pos ) ;
write ( " " ) ;
endPos = emitToken ( SyntaxKind . OpenParenToken , endPos ) ;
emit ( node . expression ) ;
emitToken ( SyntaxKind . CloseParenToken , node . expression . end ) ;
emitEmbeddedStatement ( node . thenStatement ) ;
if ( node . elseStatement ) {
writeLine ( ) ;
emitToken ( SyntaxKind . ElseKeyword , node . thenStatement . end ) ;
if ( node . elseStatement . kind === SyntaxKind . IfStatement ) {
write ( " " ) ;
emit ( node . elseStatement ) ;
2014-08-19 19:43:13 +02:00
}
else {
2014-10-11 01:44:14 +02:00
emitEmbeddedStatement ( node . elseStatement ) ;
2014-08-19 19:43:13 +02:00
}
2014-08-16 00:52:30 +02:00
}
2014-08-12 00:54:12 +02:00
}
2014-10-11 01:44:14 +02:00
function emitDoStatement ( node : DoStatement ) {
write ( "do" ) ;
emitEmbeddedStatement ( node . statement ) ;
if ( node . statement . kind === SyntaxKind . Block ) {
write ( " " ) ;
}
else {
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
}
2014-10-11 01:44:14 +02:00
write ( "while (" ) ;
emit ( node . expression ) ;
write ( ");" ) ;
2014-08-22 23:40:47 +02:00
}
2014-10-11 01:44:14 +02:00
function emitWhileStatement ( node : WhileStatement ) {
write ( "while (" ) ;
emit ( node . expression ) ;
write ( ")" ) ;
emitEmbeddedStatement ( node . statement ) ;
}
function emitForStatement ( node : ForStatement ) {
var endPos = emitToken ( SyntaxKind . ForKeyword , node . pos ) ;
write ( " " ) ;
endPos = emitToken ( SyntaxKind . OpenParenToken , endPos ) ;
2014-12-16 10:09:42 +01:00
if ( node . initializer && node . initializer . kind === SyntaxKind . VariableDeclarationList ) {
var variableDeclarationList = < VariableDeclarationList > node . initializer ;
var declarations = variableDeclarationList . declarations ;
if ( declarations [ 0 ] && isLet ( declarations [ 0 ] ) ) {
2014-11-21 05:24:08 +01:00
emitToken ( SyntaxKind . LetKeyword , endPos ) ;
}
2014-12-16 10:09:42 +01:00
else if ( declarations [ 0 ] && isConst ( declarations [ 0 ] ) ) {
2014-11-21 05:24:08 +01:00
emitToken ( SyntaxKind . ConstKeyword , endPos ) ;
}
else {
emitToken ( SyntaxKind . VarKeyword , endPos ) ;
}
2014-10-11 01:44:14 +02:00
write ( " " ) ;
2014-12-16 10:09:42 +01:00
emitCommaList ( variableDeclarationList . declarations ) ;
2014-10-11 01:44:14 +02:00
}
2014-12-16 10:09:42 +01:00
else if ( node . initializer ) {
2014-10-11 01:44:14 +02:00
emit ( node . initializer ) ;
2014-08-15 01:32:21 +02:00
}
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
emitOptional ( " " , node . condition ) ;
write ( ";" ) ;
emitOptional ( " " , node . iterator ) ;
write ( ")" ) ;
emitEmbeddedStatement ( node . statement ) ;
2014-08-12 00:54:12 +02:00
}
2014-10-11 01:44:14 +02:00
function emitForInStatement ( node : ForInStatement ) {
var endPos = emitToken ( SyntaxKind . ForKeyword , node . pos ) ;
write ( " " ) ;
endPos = emitToken ( SyntaxKind . OpenParenToken , endPos ) ;
2014-12-16 10:09:42 +01:00
if ( node . initializer . kind === SyntaxKind . VariableDeclarationList ) {
var variableDeclarationList = < VariableDeclarationList > node . initializer ;
if ( variableDeclarationList . declarations . length >= 1 ) {
var decl = variableDeclarationList . declarations [ 0 ] ;
2014-11-21 06:06:08 +01:00
if ( isLet ( decl ) ) {
2014-11-21 05:24:08 +01:00
emitToken ( SyntaxKind . LetKeyword , endPos ) ;
}
else {
emitToken ( SyntaxKind . VarKeyword , endPos ) ;
}
write ( " " ) ;
emit ( decl ) ;
}
2014-08-22 02:17:02 +02:00
}
else {
2014-12-16 10:09:42 +01:00
emit ( node . initializer ) ;
2014-08-22 02:17:02 +02:00
}
2014-10-11 01:44:14 +02:00
write ( " in " ) ;
emit ( node . expression ) ;
emitToken ( SyntaxKind . CloseParenToken , node . expression . end ) ;
emitEmbeddedStatement ( node . statement ) ;
2014-08-22 02:17:02 +02:00
}
2014-10-11 01:44:14 +02:00
function emitBreakOrContinueStatement ( node : BreakOrContinueStatement ) {
emitToken ( node . kind === SyntaxKind . BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword , node . pos ) ;
emitOptional ( " " , node . label ) ;
write ( ";" ) ;
}
2014-08-19 19:43:13 +02:00
2014-10-11 01:44:14 +02:00
function emitReturnStatement ( node : ReturnStatement ) {
emitToken ( SyntaxKind . ReturnKeyword , node . pos ) ;
emitOptional ( " " , node . expression ) ;
write ( ";" ) ;
}
2014-08-19 19:43:13 +02:00
2014-10-11 01:44:14 +02:00
function emitWithStatement ( node : WhileStatement ) {
write ( "with (" ) ;
emit ( node . expression ) ;
write ( ")" ) ;
emitEmbeddedStatement ( node . statement ) ;
}
2014-08-19 19:43:13 +02:00
2014-10-11 01:44:14 +02:00
function emitSwitchStatement ( node : SwitchStatement ) {
var endPos = emitToken ( SyntaxKind . SwitchKeyword , node . pos ) ;
write ( " " ) ;
emitToken ( SyntaxKind . OpenParenToken , endPos ) ;
emit ( node . expression ) ;
endPos = emitToken ( SyntaxKind . CloseParenToken , node . expression . end ) ;
write ( " " ) ;
emitToken ( SyntaxKind . OpenBraceToken , endPos ) ;
increaseIndent ( ) ;
emitLines ( node . clauses ) ;
decreaseIndent ( ) ;
2014-08-21 22:44:26 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emitToken ( SyntaxKind . CloseBraceToken , node . clauses . end ) ;
}
2014-08-19 19:43:13 +02:00
2014-11-21 05:24:08 +01:00
function isOnSameLine ( node1 : Node , node2 : Node ) {
return getLineOfLocalPosition ( currentSourceFile , skipTrivia ( currentSourceFile . text , node1 . pos ) ) ===
2015-02-08 21:13:56 +01:00
getLineOfLocalPosition ( currentSourceFile , skipTrivia ( currentSourceFile . text , node2 . pos ) ) ;
2014-08-19 19:43:13 +02:00
}
2014-10-11 01:44:14 +02:00
function emitCaseOrDefaultClause ( node : CaseOrDefaultClause ) {
if ( node . kind === SyntaxKind . CaseClause ) {
write ( "case " ) ;
2014-12-02 07:50:03 +01:00
emit ( ( < CaseClause > node ) . expression ) ;
2014-10-11 01:44:14 +02:00
write ( ":" ) ;
}
else {
write ( "default:" ) ;
2014-08-22 23:35:07 +02:00
}
2014-11-21 05:24:08 +01:00
if ( node . statements . length === 1 && isOnSameLine ( node , node . statements [ 0 ] ) ) {
write ( " " ) ;
emit ( node . statements [ 0 ] ) ;
}
else {
increaseIndent ( ) ;
emitLines ( node . statements ) ;
decreaseIndent ( ) ;
2014-08-19 19:43:13 +02:00
}
}
2014-10-11 01:44:14 +02:00
function emitThrowStatement ( node : ThrowStatement ) {
write ( "throw " ) ;
emit ( node . expression ) ;
write ( ";" ) ;
}
2014-08-22 23:40:47 +02:00
2014-10-11 01:44:14 +02:00
function emitTryStatement ( node : TryStatement ) {
write ( "try " ) ;
emit ( node . tryBlock ) ;
2014-12-02 08:17:34 +01:00
emit ( node . catchClause ) ;
2014-10-11 01:44:14 +02:00
if ( node . finallyBlock ) {
writeLine ( ) ;
write ( "finally " ) ;
emit ( node . finallyBlock ) ;
2014-08-22 23:40:47 +02:00
}
}
2014-12-02 08:17:34 +01:00
function emitCatchClause ( node : CatchClause ) {
2014-10-11 01:44:14 +02:00
writeLine ( ) ;
var endPos = emitToken ( SyntaxKind . CatchKeyword , node . pos ) ;
write ( " " ) ;
emitToken ( SyntaxKind . OpenParenToken , endPos ) ;
2014-12-02 08:17:34 +01:00
emit ( node . name ) ;
emitToken ( SyntaxKind . CloseParenToken , node . name . end ) ;
2014-10-11 01:44:14 +02:00
write ( " " ) ;
2014-12-02 08:17:34 +01:00
emitBlock ( node . block ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
function emitDebuggerStatement ( node : Node ) {
emitToken ( SyntaxKind . DebuggerKeyword , node . pos ) ;
write ( ";" ) ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
2014-10-11 01:44:14 +02:00
function emitLabelledStatement ( node : LabeledStatement ) {
emit ( node . label ) ;
write ( ": " ) ;
emit ( node . statement ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function getContainingModule ( node : Node ) : ModuleDeclaration {
do {
node = node . parent ;
} while ( node && node . kind !== SyntaxKind . ModuleDeclaration ) ;
return < ModuleDeclaration > node ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function emitModuleMemberName ( node : Declaration ) {
emitStart ( node . name ) ;
2014-12-17 03:50:34 +01:00
if ( getCombinedNodeFlags ( node ) & NodeFlags . Export ) {
2014-10-11 01:44:14 +02:00
var container = getContainingModule ( node ) ;
write ( container ? resolver . getLocalNameOfContainer ( container ) : "exports" ) ;
write ( "." ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
emitNode ( node . name ) ;
emitEnd ( node . name ) ;
2014-07-17 00:39:14 +02:00
}
2014-08-08 22:56:53 +02:00
2014-12-06 22:53:06 +01:00
function emitDestructuring ( root : BinaryExpression | VariableDeclaration | ParameterDeclaration , value? : Expression ) {
2014-12-04 01:43:01 +01:00
var emitCount = 0 ;
2014-12-05 02:43:15 +01:00
// An exported declaration is actually emitted as an assignment (to a property on the module object), so
2014-12-06 22:53:06 +01:00
// temporary variables in an exported declaration need to have real declarations elsewhere
2014-12-17 03:50:34 +01:00
var isDeclaration = ( root . kind === SyntaxKind . VariableDeclaration && ! ( getCombinedNodeFlags ( root ) & NodeFlags . Export ) ) || root . kind === SyntaxKind . Parameter ;
2014-12-04 01:43:01 +01:00
if ( root . kind === SyntaxKind . BinaryExpression ) {
emitAssignmentExpression ( < BinaryExpression > root ) ;
}
else {
emitBindingElement ( < BindingElement > root , value ) ;
}
function emitAssignment ( name : Identifier , value : Expression ) {
if ( emitCount ++ ) {
write ( ", " ) ;
}
2014-12-06 22:53:06 +01:00
if ( name . parent && ( name . parent . kind === SyntaxKind . VariableDeclaration || name . parent . kind === SyntaxKind . BindingElement ) ) {
emitModuleMemberName ( < Declaration > name . parent ) ;
2014-12-04 01:43:01 +01:00
}
else {
emit ( name ) ;
}
write ( " = " ) ;
emit ( value ) ;
}
function ensureIdentifier ( expr : Expression ) : Expression {
if ( expr . kind !== SyntaxKind . Identifier ) {
var identifier = createTempVariable ( root ) ;
if ( ! isDeclaration ) {
recordTempDeclaration ( identifier ) ;
}
emitAssignment ( identifier , expr ) ;
expr = identifier ;
}
return expr ;
}
function createVoidZero ( ) : Expression {
var zero = < LiteralExpression > createNode ( SyntaxKind . NumericLiteral ) ;
zero . text = "0" ;
2014-12-12 20:28:05 +01:00
var result = < VoidExpression > createNode ( SyntaxKind . VoidExpression ) ;
result . expression = zero ;
2014-12-04 01:43:01 +01:00
return result ;
}
function createDefaultValueCheck ( value : Expression , defaultValue : Expression ) : Expression {
// The value expression will be evaluated twice, so for anything but a simple identifier
// we need to generate a temporary variable
value = ensureIdentifier ( value ) ;
// Return the expression 'value === void 0 ? defaultValue : value'
var equals = < BinaryExpression > createNode ( SyntaxKind . BinaryExpression ) ;
equals . left = value ;
equals . operator = SyntaxKind . EqualsEqualsEqualsToken ;
equals . right = createVoidZero ( ) ;
var cond = < ConditionalExpression > createNode ( SyntaxKind . ConditionalExpression ) ;
cond . condition = equals ;
cond . whenTrue = defaultValue ;
cond . whenFalse = value ;
return cond ;
}
function createNumericLiteral ( value : number ) {
var node = < LiteralExpression > createNode ( SyntaxKind . NumericLiteral ) ;
node . text = "" + value ;
return node ;
}
function parenthesizeForAccess ( expr : Expression ) : LeftHandSideExpression {
if ( expr . kind === SyntaxKind . Identifier || expr . kind === SyntaxKind . PropertyAccessExpression || expr . kind === SyntaxKind . ElementAccessExpression ) {
return < LeftHandSideExpression > expr ;
}
var node = < ParenthesizedExpression > createNode ( SyntaxKind . ParenthesizedExpression ) ;
node . expression = expr ;
return node ;
}
function createPropertyAccess ( object : Expression , propName : Identifier ) : Expression {
if ( propName . kind !== SyntaxKind . Identifier ) {
return createElementAccess ( object , propName ) ;
}
var node = < PropertyAccessExpression > createNode ( SyntaxKind . PropertyAccessExpression ) ;
node . expression = parenthesizeForAccess ( object ) ;
node . name = propName ;
return node ;
}
function createElementAccess ( object : Expression , index : Expression ) : Expression {
var node = < ElementAccessExpression > createNode ( SyntaxKind . ElementAccessExpression ) ;
node . expression = parenthesizeForAccess ( object ) ;
node . argumentExpression = index ;
return node ;
}
function emitObjectLiteralAssignment ( target : ObjectLiteralExpression , value : Expression ) {
var properties = target . properties ;
if ( properties . length !== 1 ) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
value = ensureIdentifier ( value ) ;
}
for ( var i = 0 ; i < properties . length ; i ++ ) {
var p = properties [ i ] ;
if ( p . kind === SyntaxKind . PropertyAssignment || p . kind === SyntaxKind . ShorthandPropertyAssignment ) {
// TODO(andersh): Computed property support
2014-12-08 23:34:00 +01:00
var propName = < Identifier > ( ( < PropertyAssignment > p ) . name ) ;
emitDestructuringAssignment ( ( < PropertyAssignment > p ) . initializer || propName , createPropertyAccess ( value , propName ) ) ;
2014-12-04 01:43:01 +01:00
}
}
}
function emitArrayLiteralAssignment ( target : ArrayLiteralExpression , value : Expression ) {
var elements = target . elements ;
if ( elements . length !== 1 ) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
value = ensureIdentifier ( value ) ;
}
for ( var i = 0 ; i < elements . length ; i ++ ) {
var e = elements [ i ] ;
if ( e . kind !== SyntaxKind . OmittedExpression ) {
2014-12-12 02:41:24 +01:00
if ( e . kind !== SyntaxKind . SpreadElementExpression ) {
emitDestructuringAssignment ( e , createElementAccess ( value , createNumericLiteral ( i ) ) ) ;
}
else {
if ( i === elements . length - 1 ) {
value = ensureIdentifier ( value ) ;
emitAssignment ( < Identifier > ( < SpreadElementExpression > e ) . expression , value ) ;
write ( ".slice(" + i + ")" ) ;
}
}
2014-12-04 01:43:01 +01:00
}
}
}
function emitDestructuringAssignment ( target : Expression , value : Expression ) {
if ( target . kind === SyntaxKind . BinaryExpression && ( < BinaryExpression > target ) . operator === SyntaxKind . EqualsToken ) {
2015-02-08 21:13:56 +01:00
value = createDefaultValueCheck ( value , ( < BinaryExpression > target ) . right ) ;
2014-12-04 01:43:01 +01:00
target = ( < BinaryExpression > target ) . left ;
}
if ( target . kind === SyntaxKind . ObjectLiteralExpression ) {
emitObjectLiteralAssignment ( < ObjectLiteralExpression > target , value ) ;
}
else if ( target . kind === SyntaxKind . ArrayLiteralExpression ) {
emitArrayLiteralAssignment ( < ArrayLiteralExpression > target , value ) ;
}
else {
emitAssignment ( < Identifier > target , value ) ;
}
}
function emitAssignmentExpression ( root : BinaryExpression ) {
var target = root . left ;
var value = root . right ;
if ( root . parent . kind === SyntaxKind . ExpressionStatement ) {
emitDestructuringAssignment ( target , value ) ;
}
else {
if ( root . parent . kind !== SyntaxKind . ParenthesizedExpression ) {
write ( "(" ) ;
}
value = ensureIdentifier ( value ) ;
emitDestructuringAssignment ( target , value ) ;
write ( ", " ) ;
emit ( value ) ;
if ( root . parent . kind !== SyntaxKind . ParenthesizedExpression ) {
write ( ")" ) ;
}
}
}
function emitBindingElement ( target : BindingElement , value : Expression ) {
if ( target . initializer ) {
// Combine value and initializer
value = value ? createDefaultValueCheck ( value , target . initializer ) : target . initializer ;
}
else if ( ! value ) {
// Use 'void 0' in absence of value and initializer
value = createVoidZero ( ) ;
}
if ( isBindingPattern ( target . name ) ) {
var pattern = < BindingPattern > target . name ;
var elements = pattern . elements ;
if ( elements . length !== 1 ) {
// For anything but a single element destructuring we need to generate a temporary
// to ensure value is evaluated exactly once.
value = ensureIdentifier ( value ) ;
}
for ( var i = 0 ; i < elements . length ; i ++ ) {
var element = elements [ i ] ;
if ( pattern . kind === SyntaxKind . ObjectBindingPattern ) {
// Rewrite element to a declaration with an initializer that fetches property
var propName = element . propertyName || < Identifier > element . name ;
emitBindingElement ( element , createPropertyAccess ( value , propName ) ) ;
}
else if ( element . kind !== SyntaxKind . OmittedExpression ) {
2014-12-12 03:27:08 +01:00
if ( ! element . dotDotDotToken ) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement ( element , createElementAccess ( value , createNumericLiteral ( i ) ) ) ;
}
else {
if ( i === elements . length - 1 ) {
value = ensureIdentifier ( value ) ;
emitAssignment ( < Identifier > element . name , value ) ;
write ( ".slice(" + i + ")" ) ;
}
}
2014-12-04 01:43:01 +01:00
}
}
}
else {
emitAssignment ( < Identifier > target . name , value ) ;
}
}
}
2014-10-11 01:44:14 +02:00
function emitVariableDeclaration ( node : VariableDeclaration ) {
2014-12-04 01:43:01 +01:00
if ( isBindingPattern ( node . name ) ) {
2015-01-16 16:15:31 +01:00
if ( languageVersion < ScriptTarget . ES6 ) {
2014-12-14 18:43:14 +01:00
emitDestructuring ( node ) ;
}
else {
emit ( node . name ) ;
emitOptional ( " = " , node . initializer ) ;
}
2014-12-04 01:43:01 +01:00
}
else {
emitModuleMemberName ( node ) ;
emitOptional ( " = " , node . initializer ) ;
}
2014-07-19 03:06:37 +02:00
}
2014-07-16 19:49:11 +02:00
2014-10-11 01:44:14 +02:00
function emitVariableStatement ( node : VariableStatement ) {
2014-11-21 05:24:08 +01:00
if ( ! ( node . flags & NodeFlags . Export ) ) {
2014-12-16 10:09:42 +01:00
if ( isLet ( node . declarationList ) ) {
2014-11-21 05:24:08 +01:00
write ( "let " ) ;
2014-08-05 02:59:33 +02:00
}
2014-12-16 10:09:42 +01:00
else if ( isConst ( node . declarationList ) ) {
2014-11-21 05:24:08 +01:00
write ( "const " ) ;
}
else {
write ( "var " ) ;
2014-08-07 02:06:59 +02:00
}
2014-07-19 03:06:37 +02:00
}
2014-12-16 10:09:42 +01:00
emitCommaList ( node . declarationList . declarations ) ;
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
2014-07-18 23:40:47 +02:00
}
2014-07-16 19:49:11 +02:00
2014-10-11 01:44:14 +02:00
function emitParameter ( node : ParameterDeclaration ) {
2015-01-16 16:15:31 +01:00
if ( languageVersion < ScriptTarget . ES6 ) {
2014-12-14 18:43:14 +01:00
if ( isBindingPattern ( node . name ) ) {
var name = createTempVariable ( node ) ;
if ( ! tempParameters ) {
tempParameters = [ ] ;
}
tempParameters . push ( name ) ;
emit ( name ) ;
}
else {
emit ( node . name ) ;
2014-12-04 01:43:01 +01:00
}
}
else {
2014-12-14 18:43:14 +01:00
if ( node . dotDotDotToken ) {
write ( "..." ) ;
}
2014-12-04 01:43:01 +01:00
emit ( node . name ) ;
2014-12-14 18:43:14 +01:00
emitOptional ( " = " , node . initializer ) ;
2014-12-04 01:43:01 +01:00
}
2014-11-11 00:36:10 +01:00
}
2014-11-21 05:24:08 +01:00
function emitDefaultValueAssignments ( node : FunctionLikeDeclaration ) {
2015-01-16 16:15:31 +01:00
if ( languageVersion < ScriptTarget . ES6 ) {
2014-12-14 18:43:14 +01:00
var tempIndex = 0 ;
forEach ( node . parameters , p = > {
if ( isBindingPattern ( p . name ) ) {
writeLine ( ) ;
write ( "var " ) ;
emitDestructuring ( p , tempParameters [ tempIndex ] ) ;
write ( ";" ) ;
tempIndex ++ ;
}
else if ( p . initializer ) {
writeLine ( ) ;
emitStart ( p ) ;
write ( "if (" ) ;
emitNode ( p . name ) ;
write ( " === void 0)" ) ;
emitEnd ( p ) ;
write ( " { " ) ;
emitStart ( p ) ;
emitNode ( p . name ) ;
write ( " = " ) ;
emitNode ( p . initializer ) ;
emitEnd ( p ) ;
write ( "; }" ) ;
}
} ) ;
}
2014-11-11 00:36:10 +01:00
}
2014-11-21 05:24:08 +01:00
function emitRestParameter ( node : FunctionLikeDeclaration ) {
2015-01-16 16:15:31 +01:00
if ( languageVersion < ScriptTarget . ES6 && hasRestParameters ( node ) ) {
2014-10-11 01:44:14 +02:00
var restIndex = node . parameters . length - 1 ;
var restParam = node . parameters [ restIndex ] ;
2014-12-05 02:43:15 +01:00
var tempName = createTempVariable ( node , /*forLoopVariable*/ true ) . text ;
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emitLeadingComments ( restParam ) ;
emitStart ( restParam ) ;
write ( "var " ) ;
emitNode ( restParam . name ) ;
write ( " = [];" ) ;
emitEnd ( restParam ) ;
emitTrailingComments ( restParam ) ;
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
write ( "for (" ) ;
emitStart ( restParam ) ;
2014-12-04 01:43:01 +01:00
write ( "var " + tempName + " = " + restIndex + ";" ) ;
2014-10-11 01:44:14 +02:00
emitEnd ( restParam ) ;
write ( " " ) ;
emitStart ( restParam ) ;
2014-12-04 01:43:01 +01:00
write ( tempName + " < arguments.length;" ) ;
2014-10-11 01:44:14 +02:00
emitEnd ( restParam ) ;
write ( " " ) ;
emitStart ( restParam ) ;
2014-12-04 01:43:01 +01:00
write ( tempName + "++" ) ;
2014-10-11 01:44:14 +02:00
emitEnd ( restParam ) ;
write ( ") {" ) ;
increaseIndent ( ) ;
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emitStart ( restParam ) ;
emitNode ( restParam . name ) ;
2014-12-04 01:43:01 +01:00
write ( "[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];" ) ;
2014-10-11 01:44:14 +02:00
emitEnd ( restParam ) ;
decreaseIndent ( ) ;
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
write ( "}" ) ;
2014-11-11 00:36:10 +01:00
}
}
2014-10-11 01:44:14 +02:00
function emitAccessor ( node : AccessorDeclaration ) {
write ( node . kind === SyntaxKind . GetAccessor ? "get " : "set " ) ;
emit ( node . name ) ;
emitSignatureAndBody ( node ) ;
2014-07-13 01:04:16 +02:00
}
2015-01-29 02:34:38 +01:00
function shouldEmitAsArrowFunction ( node : FunctionLikeDeclaration ) : boolean {
2015-01-31 02:48:07 +01:00
return node . kind === SyntaxKind . ArrowFunction && languageVersion >= ScriptTarget . ES6 ;
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
function emitFunctionDeclaration ( node : FunctionLikeDeclaration ) {
2014-12-16 12:19:13 +01:00
if ( nodeIsMissing ( node . body ) ) {
2014-10-11 01:44:14 +02:00
return emitPinnedOrTripleSlashComments ( node ) ;
2014-07-13 01:04:16 +02:00
}
2014-12-09 01:16:11 +01:00
if ( node . kind !== SyntaxKind . MethodDeclaration && node . kind !== SyntaxKind . MethodSignature ) {
2014-10-11 01:44:14 +02:00
// Methods will emit the comments as part of emitting method declaration
emitLeadingComments ( node ) ;
2014-08-22 02:17:02 +02:00
}
2015-01-07 03:18:37 +01:00
2015-01-07 20:54:12 +01:00
// For targeting below es6, emit functions-like declaration including arrow function using function keyword.
// When targeting ES6, emit arrow function natively in ES6 by omitting function keyword and using fat arrow instead
2015-01-29 02:34:38 +01:00
if ( ! shouldEmitAsArrowFunction ( node ) ) {
2015-01-07 03:18:37 +01:00
write ( "function " ) ;
}
2014-10-11 01:44:14 +02:00
if ( node . kind === SyntaxKind . FunctionDeclaration || ( node . kind === SyntaxKind . FunctionExpression && node . name ) ) {
emit ( node . name ) ;
}
emitSignatureAndBody ( node ) ;
2014-12-09 01:16:11 +01:00
if ( node . kind !== SyntaxKind . MethodDeclaration && node . kind !== SyntaxKind . MethodSignature ) {
2014-10-11 01:44:14 +02:00
emitTrailingComments ( node ) ;
2014-08-22 02:17:02 +02:00
}
2014-11-11 00:36:10 +01:00
}
2014-10-11 01:44:14 +02:00
function emitCaptureThisForNodeIfNecessary ( node : Node ) : void {
if ( resolver . getNodeCheckFlags ( node ) & NodeCheckFlags . CaptureThis ) {
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emitStart ( node ) ;
write ( "var _this = this;" ) ;
emitEnd ( node ) ;
2014-08-14 18:01:38 +02:00
}
2014-08-14 16:48:14 +02:00
}
2014-11-21 05:24:08 +01:00
function emitSignatureParameters ( node : FunctionLikeDeclaration ) {
2014-10-11 01:44:14 +02:00
increaseIndent ( ) ;
write ( "(" ) ;
if ( node ) {
2014-12-12 01:23:57 +01:00
var parameters = node . parameters ;
2015-01-16 16:15:31 +01:00
var omitCount = languageVersion < ScriptTarget . ES6 && hasRestParameters ( node ) ? 1 : 0 ;
2014-12-14 18:43:14 +01:00
emitList ( parameters , 0 , parameters . length - omitCount , /*multiLine*/ false , /*trailingComma*/ false ) ;
2014-10-11 01:44:14 +02:00
}
write ( ")" ) ;
decreaseIndent ( ) ;
2014-11-11 00:36:10 +01:00
}
2015-01-29 01:48:53 +01:00
function emitSignatureParametersForArrow ( node : FunctionLikeDeclaration ) {
2015-01-29 02:34:38 +01:00
// Check whether the parameter list needs parentheses and preserve no-parenthesis
2015-01-30 23:09:10 +01:00
if ( node . parameters . length === 1 && node . pos === node . parameters [ 0 ] . pos ) {
emit ( node . parameters [ 0 ] ) ;
2015-01-30 01:38:05 +01:00
return ;
2015-01-29 01:48:53 +01:00
}
2015-01-30 01:07:55 +01:00
emitSignatureParameters ( node ) ;
2015-01-29 01:48:53 +01:00
}
2015-01-27 04:00:38 +01:00
2014-11-21 05:24:08 +01:00
function emitSignatureAndBody ( node : FunctionLikeDeclaration ) {
2014-12-04 01:43:01 +01:00
var saveTempCount = tempCount ;
var saveTempVariables = tempVariables ;
var saveTempParameters = tempParameters ;
tempCount = 0 ;
tempVariables = undefined ;
tempParameters = undefined ;
2015-01-07 03:18:37 +01:00
// When targeting ES6, emit arrow function natively in ES6
2015-01-29 02:34:38 +01:00
if ( shouldEmitAsArrowFunction ( node ) ) {
2015-01-29 01:48:53 +01:00
emitSignatureParametersForArrow ( node ) ;
2015-01-29 02:34:38 +01:00
write ( " =>" ) ;
}
else {
emitSignatureParameters ( node ) ;
2015-01-07 03:18:37 +01:00
}
2014-10-11 01:44:14 +02:00
write ( " {" ) ;
scopeEmitStart ( node ) ;
2014-11-11 00:36:10 +01:00
2015-02-03 00:14:19 +01:00
if ( ! node . body ) {
2014-10-11 01:44:14 +02:00
writeLine ( ) ;
write ( "}" ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else {
2015-02-03 00:50:16 +01:00
increaseIndent ( ) ;
emitDetachedComments ( node . body . kind === SyntaxKind . Block ? ( < Block > node . body ) . statements : node.body ) ;
var startIndex = 0 ;
2014-12-03 07:52:21 +01:00
if ( node . body . kind === SyntaxKind . Block ) {
2015-02-03 00:50:16 +01:00
startIndex = emitDirectivePrologues ( ( < Block > node . body ) . statements , /*startWithNewLine*/ true ) ;
2014-10-11 01:44:14 +02:00
}
2015-02-03 00:50:16 +01:00
var outPos = writer . getTextPos ( ) ;
emitCaptureThisForNodeIfNecessary ( node ) ;
emitDefaultValueAssignments ( node ) ;
emitRestParameter ( node ) ;
if ( node . body . kind !== SyntaxKind . Block && outPos === writer . getTextPos ( ) ) {
decreaseIndent ( ) ;
write ( " " ) ;
emitStart ( node . body ) ;
2014-10-11 01:44:14 +02:00
write ( "return " ) ;
2015-02-03 00:50:16 +01:00
// Don't emit comments on this body. We'll have already taken care of it above
// when we called emitDetachedComments.
emitNode ( node . body , /*disableComments:*/ true ) ;
emitEnd ( node . body ) ;
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
2015-02-03 00:50:16 +01:00
emitTempDeclarations ( /*newLine*/ false ) ;
write ( " " ) ;
2014-10-11 01:44:14 +02:00
emitStart ( node . body ) ;
write ( "}" ) ;
emitEnd ( node . body ) ;
2014-07-17 00:39:14 +02:00
}
2015-02-03 00:50:16 +01:00
else {
if ( node . body . kind === SyntaxKind . Block ) {
emitLinesStartingAt ( ( < Block > node . body ) . statements , startIndex ) ;
}
else {
writeLine ( ) ;
emitLeadingComments ( node . body ) ;
write ( "return " ) ;
emit ( node . body , /*disableComments:*/ true ) ;
write ( ";" ) ;
emitTrailingComments ( node . body ) ;
}
emitTempDeclarations ( /*newLine*/ true ) ;
writeLine ( ) ;
if ( node . body . kind === SyntaxKind . Block ) {
emitLeadingCommentsOfPosition ( ( < Block > node . body ) . statements . end ) ;
decreaseIndent ( ) ;
emitToken ( SyntaxKind . CloseBraceToken , ( < Block > node . body ) . statements . end ) ;
}
else {
decreaseIndent ( ) ;
emitStart ( node . body ) ;
write ( "}" ) ;
emitEnd ( node . body ) ;
}
}
2014-07-13 01:04:16 +02:00
}
2015-02-03 00:14:19 +01:00
2014-10-11 01:44:14 +02:00
scopeEmitEnd ( ) ;
if ( node . flags & NodeFlags . Export ) {
writeLine ( ) ;
emitStart ( node ) ;
emitModuleMemberName ( node ) ;
write ( " = " ) ;
emit ( node . name ) ;
emitEnd ( node ) ;
write ( ";" ) ;
2014-07-17 00:39:14 +02:00
}
2014-12-04 01:43:01 +01:00
tempCount = saveTempCount ;
tempVariables = saveTempVariables ;
tempParameters = saveTempParameters ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
function findInitialSuperCall ( ctor : ConstructorDeclaration ) : ExpressionStatement {
if ( ctor . body ) {
var statement = ( < Block > ctor . body ) . statements [ 0 ] ;
if ( statement && statement . kind === SyntaxKind . ExpressionStatement ) {
var expr = ( < ExpressionStatement > statement ) . expression ;
if ( expr && expr . kind === SyntaxKind . CallExpression ) {
2014-11-30 00:47:02 +01:00
var func = ( < CallExpression > expr ) . expression ;
2014-10-11 01:44:14 +02:00
if ( func && func . kind === SyntaxKind . SuperKeyword ) {
return < ExpressionStatement > statement ;
}
2014-11-11 00:36:10 +01:00
}
}
2014-08-22 23:35:07 +02:00
}
2014-08-22 23:40:47 +02:00
}
2014-11-11 00:36:10 +01:00
2014-10-11 01:44:14 +02:00
function emitParameterPropertyAssignments ( node : ConstructorDeclaration ) {
forEach ( node . parameters , param = > {
if ( param . flags & NodeFlags . AccessibilityModifier ) {
writeLine ( ) ;
emitStart ( param ) ;
emitStart ( param . name ) ;
write ( "this." ) ;
emitNode ( param . name ) ;
emitEnd ( param . name ) ;
write ( " = " ) ;
emit ( param . name ) ;
write ( ";" ) ;
emitEnd ( param ) ;
2014-11-11 00:36:10 +01:00
}
2014-10-11 01:44:14 +02:00
} ) ;
2014-07-17 00:39:14 +02:00
}
2014-11-11 00:36:10 +01:00
2014-11-18 00:53:03 +01:00
function emitMemberAccessForPropertyName ( memberName : DeclarationName ) {
2014-10-11 01:44:14 +02:00
if ( memberName . kind === SyntaxKind . StringLiteral || memberName . kind === SyntaxKind . NumericLiteral ) {
2014-11-11 00:36:10 +01:00
write ( "[" ) ;
2014-10-11 01:44:14 +02:00
emitNode ( memberName ) ;
2014-11-11 00:36:10 +01:00
write ( "]" ) ;
2014-08-22 23:35:07 +02:00
}
2014-11-18 00:53:03 +01:00
else if ( memberName . kind === SyntaxKind . ComputedPropertyName ) {
emitComputedPropertyName ( < ComputedPropertyName > memberName ) ;
}
2014-10-11 01:44:14 +02:00
else {
write ( "." ) ;
emitNode ( memberName ) ;
2014-07-17 00:39:14 +02:00
}
}
2014-10-11 01:44:14 +02:00
function emitMemberAssignments ( node : ClassDeclaration , staticFlag : NodeFlags ) {
forEach ( node . members , member = > {
2014-12-09 01:37:35 +01:00
if ( member . kind === SyntaxKind . PropertyDeclaration && ( member . flags & NodeFlags . Static ) === staticFlag && ( < PropertyDeclaration > member ) . initializer ) {
2014-11-21 01:38:57 +01:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emitLeadingComments ( member ) ;
emitStart ( member ) ;
emitStart ( ( < PropertyDeclaration > member ) . name ) ;
if ( staticFlag ) {
emitNode ( node . name ) ;
}
else {
write ( "this" ) ;
}
2014-11-18 00:53:03 +01:00
emitMemberAccessForPropertyName ( ( < PropertyDeclaration > member ) . name ) ;
2014-10-11 01:44:14 +02:00
emitEnd ( ( < PropertyDeclaration > member ) . name ) ;
write ( " = " ) ;
emit ( ( < PropertyDeclaration > member ) . initializer ) ;
write ( ";" ) ;
emitEnd ( member ) ;
emitTrailingComments ( member ) ;
2014-11-11 00:36:10 +01:00
}
2014-07-17 00:39:14 +02:00
} ) ;
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitMemberFunctions ( node : ClassDeclaration ) {
forEach ( node . members , member = > {
2014-12-09 01:16:11 +01:00
if ( member . kind === SyntaxKind . MethodDeclaration || node . kind === SyntaxKind . MethodSignature ) {
2014-10-11 01:44:14 +02:00
if ( ! ( < MethodDeclaration > member ) . body ) {
return emitPinnedOrTripleSlashComments ( member ) ;
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
writeLine ( ) ;
emitLeadingComments ( member ) ;
emitStart ( member ) ;
emitStart ( ( < MethodDeclaration > member ) . name ) ;
emitNode ( node . name ) ;
if ( ! ( member . flags & NodeFlags . Static ) ) {
write ( ".prototype" ) ;
}
2014-11-18 00:53:03 +01:00
emitMemberAccessForPropertyName ( ( < MethodDeclaration > member ) . name ) ;
2014-10-11 01:44:14 +02:00
emitEnd ( ( < MethodDeclaration > member ) . name ) ;
write ( " = " ) ;
emitStart ( member ) ;
emitFunctionDeclaration ( < MethodDeclaration > member ) ;
emitEnd ( member ) ;
emitEnd ( member ) ;
write ( ";" ) ;
emitTrailingComments ( member ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else if ( member . kind === SyntaxKind . GetAccessor || member . kind === SyntaxKind . SetAccessor ) {
var accessors = getAllAccessorDeclarations ( node , < AccessorDeclaration > member ) ;
if ( member === accessors . firstAccessor ) {
writeLine ( ) ;
emitStart ( member ) ;
write ( "Object.defineProperty(" ) ;
emitStart ( ( < AccessorDeclaration > member ) . name ) ;
emitNode ( node . name ) ;
if ( ! ( member . flags & NodeFlags . Static ) ) {
write ( ".prototype" ) ;
}
write ( ", " ) ;
2014-11-21 05:24:08 +01:00
emitExpressionForPropertyName ( ( < AccessorDeclaration > member ) . name ) ;
2014-10-11 01:44:14 +02:00
emitEnd ( ( < AccessorDeclaration > member ) . name ) ;
write ( ", {" ) ;
increaseIndent ( ) ;
if ( accessors . getAccessor ) {
writeLine ( ) ;
emitLeadingComments ( accessors . getAccessor ) ;
write ( "get: " ) ;
emitStart ( accessors . getAccessor ) ;
write ( "function " ) ;
emitSignatureAndBody ( accessors . getAccessor ) ;
emitEnd ( accessors . getAccessor ) ;
emitTrailingComments ( accessors . getAccessor ) ;
write ( "," ) ;
}
if ( accessors . setAccessor ) {
writeLine ( ) ;
emitLeadingComments ( accessors . setAccessor ) ;
write ( "set: " ) ;
emitStart ( accessors . setAccessor ) ;
write ( "function " ) ;
emitSignatureAndBody ( accessors . setAccessor ) ;
emitEnd ( accessors . setAccessor ) ;
emitTrailingComments ( accessors . setAccessor ) ;
write ( "," ) ;
}
writeLine ( ) ;
write ( "enumerable: true," ) ;
writeLine ( ) ;
write ( "configurable: true" ) ;
decreaseIndent ( ) ;
writeLine ( ) ;
write ( "});" ) ;
emitEnd ( member ) ;
}
2014-09-17 19:36:32 +02:00
}
2014-08-08 22:56:53 +02:00
} ) ;
2014-08-22 02:17:02 +02:00
}
2014-10-11 01:44:14 +02:00
function emitClassDeclaration ( node : ClassDeclaration ) {
write ( "var " ) ;
emit ( node . name ) ;
write ( " = (function (" ) ;
2014-12-01 00:38:45 +01:00
var baseTypeNode = getClassBaseTypeNode ( node ) ;
if ( baseTypeNode ) {
2014-10-11 01:44:14 +02:00
write ( "_super" ) ;
2014-08-22 02:17:02 +02:00
}
2014-10-11 01:44:14 +02:00
write ( ") {" ) ;
increaseIndent ( ) ;
scopeEmitStart ( node ) ;
2014-12-01 00:38:45 +01:00
if ( baseTypeNode ) {
2014-10-11 01:44:14 +02:00
writeLine ( ) ;
2014-12-01 00:38:45 +01:00
emitStart ( baseTypeNode ) ;
2014-10-11 01:44:14 +02:00
write ( "__extends(" ) ;
emit ( node . name ) ;
write ( ", _super);" ) ;
2014-12-01 00:38:45 +01:00
emitEnd ( baseTypeNode ) ;
2014-08-16 00:52:30 +02:00
}
2014-10-11 01:44:14 +02:00
writeLine ( ) ;
emitConstructorOfClass ( ) ;
emitMemberFunctions ( node ) ;
emitMemberAssignments ( node , NodeFlags . Static ) ;
writeLine ( ) ;
function emitClassReturnStatement() {
write ( "return " ) ;
emitNode ( node . name ) ;
2014-08-15 01:32:21 +02:00
}
2014-10-11 01:44:14 +02:00
emitToken ( SyntaxKind . CloseBraceToken , node . members . end , emitClassReturnStatement ) ;
write ( ";" ) ;
decreaseIndent ( ) ;
writeLine ( ) ;
emitToken ( SyntaxKind . CloseBraceToken , node . members . end ) ;
scopeEmitEnd ( ) ;
emitStart ( node ) ;
write ( ")(" ) ;
2014-12-01 00:38:45 +01:00
if ( baseTypeNode ) {
emit ( baseTypeNode . typeName ) ;
2014-08-22 02:17:02 +02:00
}
2014-10-11 01:44:14 +02:00
write ( ");" ) ;
emitEnd ( node ) ;
if ( node . flags & NodeFlags . Export ) {
writeLine ( ) ;
emitStart ( node ) ;
emitModuleMemberName ( node ) ;
write ( " = " ) ;
emit ( node . name ) ;
emitEnd ( node ) ;
write ( ";" ) ;
2014-08-22 02:17:02 +02:00
}
2014-08-19 19:43:13 +02:00
2014-10-11 01:44:14 +02:00
function emitConstructorOfClass() {
2014-12-04 01:43:01 +01:00
var saveTempCount = tempCount ;
var saveTempVariables = tempVariables ;
var saveTempParameters = tempParameters ;
tempCount = 0 ;
tempVariables = undefined ;
tempParameters = undefined ;
2014-10-11 01:44:14 +02:00
// Emit the constructor overload pinned comments
forEach ( node . members , member = > {
if ( member . kind === SyntaxKind . Constructor && ! ( < ConstructorDeclaration > member ) . body ) {
emitPinnedOrTripleSlashComments ( member ) ;
2014-08-19 19:43:13 +02:00
}
} ) ;
2014-10-11 01:44:14 +02:00
var ctor = getFirstConstructorWithBody ( node ) ;
if ( ctor ) {
emitLeadingComments ( ctor ) ;
2014-08-05 02:59:33 +02:00
}
2014-10-11 01:44:14 +02:00
emitStart ( < Node > ctor || node ) ;
write ( "function " ) ;
emit ( node . name ) ;
emitSignatureParameters ( ctor ) ;
write ( " {" ) ;
scopeEmitStart ( node , "constructor" ) ;
increaseIndent ( ) ;
if ( ctor ) {
emitDetachedComments ( ( < Block > ctor . body ) . statements ) ;
}
emitCaptureThisForNodeIfNecessary ( node ) ;
if ( ctor ) {
emitDefaultValueAssignments ( ctor ) ;
emitRestParameter ( ctor ) ;
2014-12-01 00:38:45 +01:00
if ( baseTypeNode ) {
2014-10-11 01:44:14 +02:00
var superCall = findInitialSuperCall ( ctor ) ;
if ( superCall ) {
writeLine ( ) ;
emit ( superCall ) ;
2014-08-19 21:06:52 +02:00
}
2014-08-19 19:43:13 +02:00
}
2014-10-11 01:44:14 +02:00
emitParameterPropertyAssignments ( ctor ) ;
}
else {
2014-12-01 00:38:45 +01:00
if ( baseTypeNode ) {
2014-10-11 01:44:14 +02:00
writeLine ( ) ;
2014-12-01 00:38:45 +01:00
emitStart ( baseTypeNode ) ;
2014-10-11 01:44:14 +02:00
write ( "_super.apply(this, arguments);" ) ;
2014-12-01 00:38:45 +01:00
emitEnd ( baseTypeNode ) ;
2014-08-07 02:58:03 +02:00
}
2014-08-07 02:06:59 +02:00
}
2014-10-11 01:44:14 +02:00
emitMemberAssignments ( node , /*nonstatic*/ 0 ) ;
if ( ctor ) {
var statements : Node [ ] = ( < Block > ctor . body ) . statements ;
if ( superCall ) statements = statements . slice ( 1 ) ;
emitLines ( statements ) ;
}
2014-12-04 01:43:01 +01:00
emitTempDeclarations ( /*newLine*/ true ) ;
2014-10-11 01:44:14 +02:00
writeLine ( ) ;
if ( ctor ) {
emitLeadingCommentsOfPosition ( ( < Block > ctor . body ) . statements . end ) ;
}
decreaseIndent ( ) ;
emitToken ( SyntaxKind . CloseBraceToken , ctor ? ( < Block > ctor . body ) . statements.end : node.members.end ) ;
scopeEmitEnd ( ) ;
emitEnd ( < Node > ctor || node ) ;
if ( ctor ) {
emitTrailingComments ( ctor ) ;
2014-08-19 19:43:13 +02:00
}
2014-12-04 01:43:01 +01:00
tempCount = saveTempCount ;
tempVariables = saveTempVariables ;
tempParameters = saveTempParameters ;
2014-08-19 19:43:13 +02:00
}
}
2014-10-11 01:44:14 +02:00
function emitInterfaceDeclaration ( node : InterfaceDeclaration ) {
emitPinnedOrTripleSlashComments ( node ) ;
2014-08-05 02:59:33 +02:00
}
2014-08-22 23:40:47 +02:00
2015-01-23 00:58:00 +01:00
function shouldEmitEnumDeclaration ( node : EnumDeclaration ) {
var isConstEnum = isConst ( node ) ;
return ! isConstEnum || compilerOptions . preserveConstEnums ;
}
2014-10-11 01:44:14 +02:00
function emitEnumDeclaration ( node : EnumDeclaration ) {
2014-11-21 05:24:08 +01:00
// const enums are completely erased during compilation.
2015-01-23 00:58:00 +01:00
if ( ! shouldEmitEnumDeclaration ( node ) ) {
2014-11-21 05:24:08 +01:00
return ;
2014-08-05 02:59:33 +02:00
}
2015-01-23 00:58:00 +01:00
2014-10-11 01:44:14 +02:00
if ( ! ( node . flags & NodeFlags . Export ) ) {
emitStart ( node ) ;
write ( "var " ) ;
emit ( node . name ) ;
emitEnd ( node ) ;
2014-11-11 00:36:10 +01:00
write ( ";" ) ;
2014-08-05 02:59:33 +02:00
}
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emitStart ( node ) ;
write ( "(function (" ) ;
emitStart ( node . name ) ;
write ( resolver . getLocalNameOfContainer ( node ) ) ;
emitEnd ( node . name ) ;
write ( ") {" ) ;
increaseIndent ( ) ;
scopeEmitStart ( node ) ;
2015-01-22 23:45:55 +01:00
emitLines ( node . members ) ;
2014-10-11 01:44:14 +02:00
decreaseIndent ( ) ;
writeLine ( ) ;
emitToken ( SyntaxKind . CloseBraceToken , node . members . end ) ;
scopeEmitEnd ( ) ;
write ( ")(" ) ;
emitModuleMemberName ( node ) ;
write ( " || (" ) ;
emitModuleMemberName ( node ) ;
write ( " = {}));" ) ;
emitEnd ( node ) ;
if ( node . flags & NodeFlags . Export ) {
writeLine ( ) ;
emitStart ( node ) ;
write ( "var " ) ;
emit ( node . name ) ;
write ( " = " ) ;
emitModuleMemberName ( node ) ;
emitEnd ( node ) ;
write ( ";" ) ;
2014-08-22 23:40:47 +02:00
}
2015-01-22 23:45:55 +01:00
}
2014-08-22 23:40:47 +02:00
2015-01-22 23:45:55 +01:00
function emitEnumMember ( node : EnumMember ) {
var enumParent = < EnumDeclaration > node . parent ;
emitStart ( node ) ;
write ( resolver . getLocalNameOfContainer ( enumParent ) ) ;
write ( "[" ) ;
write ( resolver . getLocalNameOfContainer ( enumParent ) ) ;
write ( "[" ) ;
emitExpressionForPropertyName ( node . name ) ;
write ( "] = " ) ;
2015-02-03 00:50:16 +01:00
writeEnumMemberDeclarationValue ( node ) ;
2015-01-22 23:45:55 +01:00
write ( "] = " ) ;
emitExpressionForPropertyName ( node . name ) ;
emitEnd ( node ) ;
write ( ";" ) ;
2014-07-18 23:40:47 +02:00
}
2014-07-16 19:49:11 +02:00
2015-02-03 00:14:19 +01:00
function writeEnumMemberDeclarationValue ( member : EnumMember ) {
if ( ! member . initializer || isConst ( member . parent ) ) {
2015-02-06 03:26:56 +01:00
var value = resolver . getConstantValue ( member ) ;
2015-02-03 00:14:19 +01:00
if ( value !== undefined ) {
write ( value . toString ( ) ) ;
return ;
}
}
if ( member . initializer ) {
emit ( member . initializer ) ;
}
else {
write ( "undefined" ) ;
2014-07-19 03:06:37 +02:00
}
2014-07-18 23:40:47 +02:00
}
2014-07-16 19:49:11 +02:00
2014-10-11 01:44:14 +02:00
function getInnerMostModuleDeclarationFromDottedModule ( module Declaration : ModuleDeclaration ) : ModuleDeclaration {
if ( module Declaration.body.kind === SyntaxKind . ModuleDeclaration ) {
var recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule ( < ModuleDeclaration > module Declaration.body ) ;
return recursiveInnerModule || < ModuleDeclaration > module Declaration.body ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2015-01-28 02:09:57 +01:00
function shouldEmitModuleDeclaration ( node : ModuleDeclaration ) {
2015-01-23 00:58:00 +01:00
return isInstantiatedModule ( node , compilerOptions . preserveConstEnums ) ;
}
2014-10-11 01:44:14 +02:00
function emitModuleDeclaration ( node : ModuleDeclaration ) {
2014-12-18 02:00:42 +01:00
// Emit only if this module is non-ambient.
2015-01-28 02:09:57 +01:00
var shouldEmit = shouldEmitModuleDeclaration ( node ) ;
2014-07-13 01:04:16 +02:00
2014-11-26 10:06:10 +01:00
if ( ! shouldEmit ) {
2014-10-11 01:44:14 +02:00
return emitPinnedOrTripleSlashComments ( node ) ;
2014-08-14 18:01:38 +02:00
}
2015-01-23 00:58:00 +01:00
2014-10-11 01:44:14 +02:00
emitStart ( node ) ;
write ( "var " ) ;
emit ( node . name ) ;
2014-07-17 00:39:14 +02:00
write ( ";" ) ;
2014-10-11 01:44:14 +02:00
emitEnd ( node ) ;
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emitStart ( node ) ;
write ( "(function (" ) ;
emitStart ( node . name ) ;
write ( resolver . getLocalNameOfContainer ( node ) ) ;
emitEnd ( node . name ) ;
write ( ") " ) ;
if ( node . body . kind === SyntaxKind . ModuleBlock ) {
2014-12-04 01:43:01 +01:00
var saveTempCount = tempCount ;
var saveTempVariables = tempVariables ;
tempCount = 0 ;
tempVariables = undefined ;
2014-10-11 01:44:14 +02:00
emit ( node . body ) ;
2014-12-04 01:43:01 +01:00
tempCount = saveTempCount ;
tempVariables = saveTempVariables ;
2014-07-13 01:04:16 +02:00
}
2014-07-17 00:39:14 +02:00
else {
2014-10-11 01:44:14 +02:00
write ( "{" ) ;
2014-07-17 00:39:14 +02:00
increaseIndent ( ) ;
2014-10-11 01:44:14 +02:00
scopeEmitStart ( node ) ;
emitCaptureThisForNodeIfNecessary ( node ) ;
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
emit ( node . body ) ;
2014-07-17 00:39:14 +02:00
decreaseIndent ( ) ;
writeLine ( ) ;
2014-11-30 23:06:15 +01:00
var module Block = < ModuleBlock > getInnerMostModuleDeclarationFromDottedModule ( node ) . body ;
2014-10-11 01:44:14 +02:00
emitToken ( SyntaxKind . CloseBraceToken , module Block.statements.end ) ;
scopeEmitEnd ( ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
write ( ")(" ) ;
if ( node . flags & NodeFlags . Export ) {
emit ( node . name ) ;
2014-07-17 00:39:14 +02:00
write ( " = " ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
emitModuleMemberName ( node ) ;
write ( " || (" ) ;
emitModuleMemberName ( node ) ;
write ( " = {}));" ) ;
emitEnd ( node ) ;
2014-07-17 00:39:14 +02:00
}
2015-02-08 17:03:15 +01:00
function emitRequire ( module Name : Expression ) {
2015-02-09 02:33:45 +01:00
if ( module Name.kind === SyntaxKind . StringLiteral ) {
2015-02-08 17:03:15 +01:00
write ( "require(" ) ;
emitStart ( module Name ) ;
emitLiteral ( < LiteralExpression > module Name ) ;
emitEnd ( module Name ) ;
emitToken ( SyntaxKind . CloseParenToken , module Name.end ) ;
write ( ";" ) ;
}
else {
write ( "require();" ) ;
}
}
function emitImportAssignment ( node : Declaration , module Name : Expression ) {
if ( ! ( node . flags & NodeFlags . Export ) ) write ( "var " ) ;
emitModuleMemberName ( < Declaration > node ) ;
write ( " = " ) ;
emitRequire ( module Name ) ;
}
function emitNamedImportAssignments ( namedImports : NamedImports , module Reference : Identifier ) {
var elements = namedImports . elements ;
for ( var i = 0 ; i < elements . length ; i ++ ) {
var element = elements [ i ] ;
if ( resolver . isReferencedImportDeclaration ( element ) ) {
writeLine ( ) ;
if ( ! ( element . flags & NodeFlags . Export ) ) write ( "var " ) ;
emitModuleMemberName ( element ) ;
write ( " = " ) ;
emit ( module Reference ) ;
write ( "." ) ;
emit ( element . propertyName || element . name ) ;
write ( ";" ) ;
}
}
}
2015-02-08 21:13:56 +01:00
function emitImportDeclaration ( node : ImportDeclaration | ImportEqualsDeclaration ) {
var info = getExternalImportInfo ( node ) ;
if ( info ) {
var declarationNode = info . declarationNode ;
var namedImports = info . namedImports ;
if ( compilerOptions . module !== ModuleKind . AMD ) {
emitLeadingComments ( node ) ;
emitStart ( node ) ;
var module Name = getImportedModuleName ( info . importNode ) ;
if ( declarationNode ) {
if ( ! ( declarationNode . flags & NodeFlags . Export ) ) write ( "var " ) ;
emitModuleMemberName ( declarationNode ) ;
write ( " = " ) ;
emitRequire ( module Name ) ;
}
else if ( namedImports ) {
write ( "var " ) ;
emit ( info . tempName ) ;
write ( " = " ) ;
emitRequire ( module Name ) ;
emitNamedImportAssignments ( namedImports , info . tempName ) ;
2015-02-08 17:03:15 +01:00
}
else {
2015-02-08 21:13:56 +01:00
emitRequire ( module Name ) ;
2015-02-08 17:03:15 +01:00
}
2015-02-08 21:13:56 +01:00
emitEnd ( node ) ;
emitTrailingComments ( node ) ;
2015-02-08 17:03:15 +01:00
}
2015-02-08 21:13:56 +01:00
else {
if ( declarationNode ) {
if ( declarationNode . flags & NodeFlags . Export ) {
emitModuleMemberName ( declarationNode ) ;
2015-02-08 17:03:15 +01:00
write ( " = " ) ;
2015-02-08 21:13:56 +01:00
emit ( declarationNode . name ) ;
write ( ";" ) ;
2015-02-08 17:03:15 +01:00
}
}
2015-02-08 21:13:56 +01:00
else if ( namedImports ) {
emitNamedImportAssignments ( namedImports , info . tempName ) ;
}
2015-02-08 17:03:15 +01:00
}
}
}
2015-01-27 23:42:20 +01:00
function emitImportEqualsDeclaration ( node : ImportEqualsDeclaration ) {
2015-02-08 21:13:56 +01:00
if ( isExternalModuleImportEqualsDeclaration ( node ) ) {
emitImportDeclaration ( node ) ;
return ;
2014-07-13 01:04:16 +02:00
}
2015-02-08 21:13:56 +01:00
// preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when
// - current file is not external module
// - import declaration is top level and target is value imported by entity name
if ( resolver . isReferencedImportDeclaration ( node ) ||
( ! isExternalModule ( currentSourceFile ) && resolver . isTopLevelValueImportEqualsWithEntityName ( node ) ) ) {
emitLeadingComments ( node ) ;
emitStart ( node ) ;
if ( ! ( node . flags & NodeFlags . Export ) ) write ( "var " ) ;
emitModuleMemberName ( node ) ;
write ( " = " ) ;
emit ( node . module Reference ) ;
write ( ";" ) ;
emitEnd ( node ) ;
emitTrailingComments ( node ) ;
2014-07-13 01:04:16 +02:00
}
}
2014-07-10 01:12:16 +02:00
2015-02-08 21:13:56 +01:00
function createExternalImportInfo ( node : Node ) : ExternalImportInfo {
2015-02-08 17:03:15 +01:00
if ( node . kind === SyntaxKind . ImportEqualsDeclaration ) {
2015-02-08 21:13:56 +01:00
if ( ( < ImportEqualsDeclaration > node ) . module Reference.kind === SyntaxKind . ExternalModuleReference ) {
return {
importNode : < ImportEqualsDeclaration > node ,
declarationNode : < ImportEqualsDeclaration > node
} ;
}
2015-02-08 17:03:15 +01:00
}
2015-02-08 21:13:56 +01:00
else if ( node . kind === SyntaxKind . ImportDeclaration ) {
2015-02-08 17:03:15 +01:00
var importClause = ( < ImportDeclaration > node ) . importClause ;
if ( importClause ) {
if ( importClause . name ) {
2015-02-08 21:13:56 +01:00
return {
importNode : < ImportDeclaration > node ,
declarationNode : importClause
} ;
2015-02-08 17:03:15 +01:00
}
2015-02-08 21:13:56 +01:00
if ( importClause . namedBindings . kind === SyntaxKind . NamespaceImport ) {
return {
importNode : < ImportDeclaration > node ,
declarationNode : < NamespaceImport > importClause . namedBindings
} ;
2015-02-08 17:03:15 +01:00
}
2015-02-08 21:13:56 +01:00
return {
importNode : < ImportDeclaration > node ,
namedImports : < NamedImports > importClause . namedBindings
} ;
}
return {
importNode : < ImportDeclaration > node
2015-02-08 17:03:15 +01:00
}
}
}
2015-02-08 21:13:56 +01:00
function createExternalImports ( sourceFile : SourceFile ) {
externalImports = [ ] ;
2015-02-08 17:03:15 +01:00
forEach ( sourceFile . statements , node = > {
2015-02-08 21:13:56 +01:00
var info = createExternalImportInfo ( node ) ;
if ( info ) {
if ( ( ! info . declarationNode && ! info . namedImports ) || resolver . isReferencedImportDeclaration ( node ) ) {
if ( ! info . declarationNode ) {
info . tempName = createTempVariable ( sourceFile ) ;
}
externalImports . push ( info ) ;
}
2015-02-08 17:03:15 +01:00
}
} ) ;
2015-02-08 21:13:56 +01:00
}
function getExternalImportInfo ( node : ImportDeclaration | ImportEqualsDeclaration ) : ExternalImportInfo {
if ( externalImports ) {
for ( var i = 0 ; i < externalImports . length ; i ++ ) {
var info = externalImports [ i ] ;
if ( info . importNode === node ) {
return info ;
}
}
}
2015-02-08 17:03:15 +01:00
}
2014-10-11 01:44:14 +02:00
function getFirstExportAssignment ( sourceFile : SourceFile ) {
return forEach ( sourceFile . statements , node = > {
if ( node . kind === SyntaxKind . ExportAssignment ) {
return < ExportAssignment > node ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
} ) ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function emitAMDModule ( node : SourceFile , startIndex : number ) {
2014-07-13 01:04:16 +02:00
writeLine ( ) ;
2014-11-21 05:24:08 +01:00
write ( "define(" ) ;
if ( node . amdModuleName ) {
write ( "\"" + node . amdModuleName + "\", " ) ;
2014-07-17 00:39:14 +02:00
}
2014-11-21 05:24:08 +01:00
write ( "[\"require\", \"exports\"" ) ;
2015-02-08 21:13:56 +01:00
forEach ( externalImports , info = > {
2014-10-11 01:44:14 +02:00
write ( ", " ) ;
2015-02-08 21:13:56 +01:00
var module Name = getImportedModuleName ( info . importNode ) ;
2015-02-09 02:33:45 +01:00
if ( module Name.kind === SyntaxKind . StringLiteral ) {
emitLiteral ( < LiteralExpression > module Name ) ;
2015-02-08 17:03:15 +01:00
}
else {
write ( "\"\"" ) ;
}
2014-10-11 01:44:14 +02:00
} ) ;
forEach ( node . amdDependencies , amdDependency = > {
var text = "\"" + amdDependency + "\"" ;
write ( ", " ) ;
write ( text ) ;
} ) ;
write ( "], function (require, exports" ) ;
2015-02-08 21:13:56 +01:00
forEach ( externalImports , info = > {
2014-10-11 01:44:14 +02:00
write ( ", " ) ;
2015-02-08 21:13:56 +01:00
emit ( info . declarationNode ? info.declarationNode.name : info.tempName ) ;
2014-10-11 01:44:14 +02:00
} ) ;
write ( ") {" ) ;
increaseIndent ( ) ;
emitCaptureThisForNodeIfNecessary ( node ) ;
emitLinesStartingAt ( node . statements , startIndex ) ;
2014-12-12 02:41:24 +01:00
emitTempDeclarations ( /*newLine*/ true ) ;
2014-10-11 01:44:14 +02:00
var exportName = resolver . getExportAssignmentName ( node ) ;
if ( exportName ) {
writeLine ( ) ;
2014-12-12 02:41:24 +01:00
var exportAssignment = getFirstExportAssignment ( node ) ;
emitStart ( exportAssignment ) ;
2014-10-11 01:44:14 +02:00
write ( "return " ) ;
2014-12-12 02:41:24 +01:00
emitStart ( exportAssignment . exportName ) ;
2014-10-11 01:44:14 +02:00
write ( exportName ) ;
2014-12-12 02:41:24 +01:00
emitEnd ( exportAssignment . exportName ) ;
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
2014-12-12 02:41:24 +01:00
emitEnd ( exportAssignment ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
decreaseIndent ( ) ;
writeLine ( ) ;
write ( "});" ) ;
2014-07-12 00:13:01 +02:00
}
2014-10-11 01:44:14 +02:00
function emitCommonJSModule ( node : SourceFile , startIndex : number ) {
emitCaptureThisForNodeIfNecessary ( node ) ;
emitLinesStartingAt ( node . statements , startIndex ) ;
2014-12-12 02:41:24 +01:00
emitTempDeclarations ( /*newLine*/ true ) ;
2014-10-11 01:44:14 +02:00
var exportName = resolver . getExportAssignmentName ( node ) ;
if ( exportName ) {
writeLine ( ) ;
2014-12-12 02:41:24 +01:00
var exportAssignment = getFirstExportAssignment ( node ) ;
emitStart ( exportAssignment ) ;
2014-10-11 01:44:14 +02:00
write ( "module.exports = " ) ;
2014-12-12 02:41:24 +01:00
emitStart ( exportAssignment . exportName ) ;
2014-10-11 01:44:14 +02:00
write ( exportName ) ;
2014-12-12 02:41:24 +01:00
emitEnd ( exportAssignment . exportName ) ;
2014-10-11 01:44:14 +02:00
write ( ";" ) ;
2014-12-12 02:41:24 +01:00
emitEnd ( exportAssignment ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-08-04 21:06:07 +02:00
2014-11-30 23:06:15 +01:00
function emitDirectivePrologues ( statements : Node [ ] , startWithNewLine : boolean ) : number {
2014-10-11 01:44:14 +02:00
for ( var i = 0 ; i < statements . length ; ++ i ) {
if ( isPrologueDirective ( statements [ i ] ) ) {
if ( startWithNewLine || i > 0 ) {
writeLine ( ) ;
2014-07-19 03:07:38 +02:00
}
2014-10-11 01:44:14 +02:00
emit ( statements [ i ] ) ;
2014-07-19 03:07:38 +02:00
}
2014-10-11 01:44:14 +02:00
else {
// return index of the first non prologue directive
return i ;
2014-07-19 03:07:38 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
return statements . length ;
2014-07-12 01:36:06 +02:00
}
2014-10-11 01:44:14 +02:00
function emitSourceFile ( node : SourceFile ) {
currentSourceFile = node ;
// Start new file on new line
writeLine ( ) ;
emitDetachedComments ( node ) ;
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
// emit prologue directives prior to __extends
var startIndex = emitDirectivePrologues ( node . statements , /*startWithNewLine*/ false ) ;
if ( ! extendsEmitted && resolver . getNodeCheckFlags ( node ) & NodeCheckFlags . EmitExtends ) {
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
write ( "var __extends = this.__extends || function (d, b) {" ) ;
2014-07-17 00:39:14 +02:00
increaseIndent ( ) ;
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
write ( "for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];" ) ;
2014-07-17 00:39:14 +02:00
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
write ( "function __() { this.constructor = d; }" ) ;
writeLine ( ) ;
write ( "__.prototype = b.prototype;" ) ;
writeLine ( ) ;
write ( "d.prototype = new __();" ) ;
2014-07-17 00:39:14 +02:00
decreaseIndent ( ) ;
writeLine ( ) ;
2014-10-11 01:44:14 +02:00
write ( "};" ) ;
extendsEmitted = true ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
if ( isExternalModule ( node ) ) {
2015-02-08 21:13:56 +01:00
createExternalImports ( node ) ;
2014-10-11 01:44:14 +02:00
if ( compilerOptions . module === ModuleKind . AMD ) {
emitAMDModule ( node , startIndex ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
else {
emitCommonJSModule ( node , startIndex ) ;
2014-07-17 00:39:14 +02:00
}
2014-07-12 00:13:01 +02:00
}
2014-10-11 01:44:14 +02:00
else {
emitCaptureThisForNodeIfNecessary ( node ) ;
emitLinesStartingAt ( node . statements , startIndex ) ;
2014-12-12 02:41:24 +01:00
emitTempDeclarations ( /*newLine*/ true ) ;
2014-07-12 00:13:01 +02:00
}
2014-07-13 01:04:16 +02:00
2014-12-03 01:09:41 +01:00
emitLeadingComments ( node . endOfFileToken ) ;
2014-07-13 01:04:16 +02:00
}
2015-01-23 00:58:00 +01:00
function emitNode ( node : Node , disableComments? :boolean ) : void {
2014-10-11 01:44:14 +02:00
if ( ! node ) {
return ;
2014-07-13 01:04:16 +02:00
}
2014-12-16 10:09:42 +01:00
2014-10-11 01:44:14 +02:00
if ( node . flags & NodeFlags . Ambient ) {
return emitPinnedOrTripleSlashComments ( node ) ;
2014-07-12 00:13:01 +02:00
}
2015-01-23 00:58:00 +01:00
var emitComments = ! disableComments && shouldEmitLeadingAndTrailingComments ( node ) ;
if ( emitComments ) {
emitLeadingComments ( node ) ;
}
emitJavaScriptWorker ( node ) ;
if ( emitComments ) {
emitTrailingComments ( node ) ;
}
}
function shouldEmitLeadingAndTrailingComments ( node : Node ) {
switch ( node . kind ) {
2015-01-28 02:16:28 +01:00
// All of these entities are emitted in a specialized fashion. As such, we allow
2015-01-23 00:58:00 +01:00
// the specilized methods for each to handle the comments on the nodes.
case SyntaxKind . InterfaceDeclaration :
case SyntaxKind . FunctionDeclaration :
case SyntaxKind . ImportDeclaration :
2015-02-08 17:03:15 +01:00
case SyntaxKind . ImportEqualsDeclaration :
2015-01-23 00:58:00 +01:00
case SyntaxKind . TypeAliasDeclaration :
case SyntaxKind . ExportAssignment :
return false ;
case SyntaxKind . ModuleDeclaration :
// Only emit the leading/trailing comments for a module if we're actually
// emitting the module as well.
2015-01-28 02:09:57 +01:00
return shouldEmitModuleDeclaration ( < ModuleDeclaration > node ) ;
2015-01-23 00:58:00 +01:00
case SyntaxKind . EnumDeclaration :
// Only emit the leading/trailing comments for an enum if we're actually
// emitting the module as well.
return shouldEmitEnumDeclaration ( < EnumDeclaration > node ) ;
}
// Emit comments for everything else.
return true ;
}
function emitJavaScriptWorker ( node : Node ) {
2014-12-02 22:29:49 +01:00
// Check if the node can be emitted regardless of the ScriptTarget
2014-10-11 01:44:14 +02:00
switch ( node . kind ) {
case SyntaxKind . Identifier :
return emitIdentifier ( < Identifier > node ) ;
case SyntaxKind . Parameter :
return emitParameter ( < ParameterDeclaration > node ) ;
2014-12-09 20:26:43 +01:00
case SyntaxKind . MethodDeclaration :
case SyntaxKind . MethodSignature :
2014-12-08 23:34:00 +01:00
return emitMethod ( < MethodDeclaration > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . GetAccessor :
case SyntaxKind . SetAccessor :
return emitAccessor ( < AccessorDeclaration > node ) ;
case SyntaxKind . ThisKeyword :
return emitThis ( node ) ;
case SyntaxKind . SuperKeyword :
return emitSuper ( node ) ;
case SyntaxKind . NullKeyword :
return write ( "null" ) ;
case SyntaxKind . TrueKeyword :
return write ( "true" ) ;
case SyntaxKind . FalseKeyword :
return write ( "false" ) ;
case SyntaxKind . NumericLiteral :
case SyntaxKind . StringLiteral :
case SyntaxKind . RegularExpressionLiteral :
2014-11-21 05:24:08 +01:00
case SyntaxKind . NoSubstitutionTemplateLiteral :
case SyntaxKind . TemplateHead :
case SyntaxKind . TemplateMiddle :
case SyntaxKind . TemplateTail :
2014-10-11 01:44:14 +02:00
return emitLiteral ( < LiteralExpression > node ) ;
2014-11-21 05:24:08 +01:00
case SyntaxKind . TemplateExpression :
return emitTemplateExpression ( < TemplateExpression > node ) ;
case SyntaxKind . TemplateSpan :
return emitTemplateSpan ( < TemplateSpan > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . QualifiedName :
2014-11-30 01:48:28 +01:00
return emitQualifiedName ( < QualifiedName > node ) ;
2014-12-04 01:43:01 +01:00
case SyntaxKind . ObjectBindingPattern :
return emitObjectBindingPattern ( < BindingPattern > node ) ;
case SyntaxKind . ArrayBindingPattern :
return emitArrayBindingPattern ( < BindingPattern > node ) ;
2014-12-14 18:43:14 +01:00
case SyntaxKind . BindingElement :
return emitBindingElement ( < BindingElement > node ) ;
2014-11-30 00:58:55 +01:00
case SyntaxKind . ArrayLiteralExpression :
return emitArrayLiteral ( < ArrayLiteralExpression > node ) ;
case SyntaxKind . ObjectLiteralExpression :
return emitObjectLiteral ( < ObjectLiteralExpression > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . PropertyAssignment :
return emitPropertyAssignment ( < PropertyDeclaration > node ) ;
2014-12-08 23:34:00 +01:00
case SyntaxKind . ShorthandPropertyAssignment :
return emitShorthandPropertyAssignment ( < ShorthandPropertyAssignment > node ) ;
2014-11-18 00:53:03 +01:00
case SyntaxKind . ComputedPropertyName :
return emitComputedPropertyName ( < ComputedPropertyName > node ) ;
2014-11-30 00:58:55 +01:00
case SyntaxKind . PropertyAccessExpression :
return emitPropertyAccess ( < PropertyAccessExpression > node ) ;
2014-11-30 00:47:02 +01:00
case SyntaxKind . ElementAccessExpression :
return emitIndexedAccess ( < ElementAccessExpression > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . CallExpression :
return emitCallExpression ( < CallExpression > node ) ;
case SyntaxKind . NewExpression :
return emitNewExpression ( < NewExpression > node ) ;
2014-11-21 05:24:08 +01:00
case SyntaxKind . TaggedTemplateExpression :
return emitTaggedTemplateExpression ( < TaggedTemplateExpression > node ) ;
2014-11-30 00:58:55 +01:00
case SyntaxKind . TypeAssertionExpression :
2014-11-30 00:47:02 +01:00
return emit ( ( < TypeAssertion > node ) . expression ) ;
2014-11-30 00:58:55 +01:00
case SyntaxKind . ParenthesizedExpression :
return emitParenExpression ( < ParenthesizedExpression > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . FunctionDeclaration :
case SyntaxKind . FunctionExpression :
case SyntaxKind . ArrowFunction :
2014-11-21 05:24:08 +01:00
return emitFunctionDeclaration ( < FunctionLikeDeclaration > node ) ;
2014-11-29 22:43:30 +01:00
case SyntaxKind . DeleteExpression :
return emitDeleteExpression ( < DeleteExpression > node ) ;
case SyntaxKind . TypeOfExpression :
return emitTypeOfExpression ( < TypeOfExpression > node ) ;
case SyntaxKind . VoidExpression :
return emitVoidExpression ( < VoidExpression > node ) ;
case SyntaxKind . PrefixUnaryExpression :
2014-11-30 01:48:28 +01:00
return emitPrefixUnaryExpression ( < PrefixUnaryExpression > node ) ;
2014-11-30 00:58:55 +01:00
case SyntaxKind . PostfixUnaryExpression :
2014-11-30 01:48:28 +01:00
return emitPostfixUnaryExpression ( < PostfixUnaryExpression > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . BinaryExpression :
return emitBinaryExpression ( < BinaryExpression > node ) ;
case SyntaxKind . ConditionalExpression :
return emitConditionalExpression ( < ConditionalExpression > node ) ;
2014-12-12 01:23:57 +01:00
case SyntaxKind . SpreadElementExpression :
return emitSpreadElementExpression ( < SpreadElementExpression > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . OmittedExpression :
return ;
case SyntaxKind . Block :
case SyntaxKind . ModuleBlock :
return emitBlock ( < Block > node ) ;
case SyntaxKind . VariableStatement :
return emitVariableStatement ( < VariableStatement > node ) ;
case SyntaxKind . EmptyStatement :
return write ( ";" ) ;
case SyntaxKind . ExpressionStatement :
return emitExpressionStatement ( < ExpressionStatement > node ) ;
case SyntaxKind . IfStatement :
return emitIfStatement ( < IfStatement > node ) ;
case SyntaxKind . DoStatement :
return emitDoStatement ( < DoStatement > node ) ;
case SyntaxKind . WhileStatement :
return emitWhileStatement ( < WhileStatement > node ) ;
case SyntaxKind . ForStatement :
return emitForStatement ( < ForStatement > node ) ;
case SyntaxKind . ForInStatement :
return emitForInStatement ( < ForInStatement > node ) ;
case SyntaxKind . ContinueStatement :
case SyntaxKind . BreakStatement :
return emitBreakOrContinueStatement ( < BreakOrContinueStatement > node ) ;
case SyntaxKind . ReturnStatement :
return emitReturnStatement ( < ReturnStatement > node ) ;
case SyntaxKind . WithStatement :
return emitWithStatement ( < WithStatement > node ) ;
case SyntaxKind . SwitchStatement :
return emitSwitchStatement ( < SwitchStatement > node ) ;
case SyntaxKind . CaseClause :
case SyntaxKind . DefaultClause :
return emitCaseOrDefaultClause ( < CaseOrDefaultClause > node ) ;
case SyntaxKind . LabeledStatement :
return emitLabelledStatement ( < LabeledStatement > node ) ;
case SyntaxKind . ThrowStatement :
return emitThrowStatement ( < ThrowStatement > node ) ;
case SyntaxKind . TryStatement :
return emitTryStatement ( < TryStatement > node ) ;
2014-12-02 08:17:34 +01:00
case SyntaxKind . CatchClause :
return emitCatchClause ( < CatchClause > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . DebuggerStatement :
return emitDebuggerStatement ( node ) ;
case SyntaxKind . VariableDeclaration :
return emitVariableDeclaration ( < VariableDeclaration > node ) ;
case SyntaxKind . ClassDeclaration :
return emitClassDeclaration ( < ClassDeclaration > node ) ;
case SyntaxKind . InterfaceDeclaration :
return emitInterfaceDeclaration ( < InterfaceDeclaration > node ) ;
case SyntaxKind . EnumDeclaration :
return emitEnumDeclaration ( < EnumDeclaration > node ) ;
2015-01-22 23:45:55 +01:00
case SyntaxKind . EnumMember :
return emitEnumMember ( < EnumMember > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . ModuleDeclaration :
return emitModuleDeclaration ( < ModuleDeclaration > node ) ;
2015-02-08 17:03:15 +01:00
case SyntaxKind . ImportDeclaration :
return emitImportDeclaration ( < ImportDeclaration > node ) ;
2015-01-27 23:42:20 +01:00
case SyntaxKind . ImportEqualsDeclaration :
return emitImportEqualsDeclaration ( < ImportEqualsDeclaration > node ) ;
2014-10-11 01:44:14 +02:00
case SyntaxKind . SourceFile :
return emitSourceFile ( < SourceFile > node ) ;
2014-08-07 03:42:14 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-10-11 01:44:14 +02:00
function hasDetachedComments ( pos : number ) {
return detachedCommentsInfo !== undefined && detachedCommentsInfo [ detachedCommentsInfo . length - 1 ] . nodePos === pos ;
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function getLeadingCommentsWithoutDetachedComments() {
// get the leading comments from detachedPos
var leadingComments = getLeadingCommentRanges ( currentSourceFile . text , detachedCommentsInfo [ detachedCommentsInfo . length - 1 ] . detachedCommentEndPos ) ;
if ( detachedCommentsInfo . length - 1 ) {
detachedCommentsInfo . pop ( ) ;
2014-07-17 00:39:14 +02:00
}
else {
2014-10-11 01:44:14 +02:00
detachedCommentsInfo = undefined ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
return leadingComments ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function getLeadingCommentsToEmit ( node : Node ) {
// Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments
2015-01-23 00:58:00 +01:00
if ( node . parent ) {
if ( node . parent . kind === SyntaxKind . SourceFile || node . pos !== node . parent . pos ) {
var leadingComments : CommentRange [ ] ;
if ( hasDetachedComments ( node . pos ) ) {
// get comments without detached comments
leadingComments = getLeadingCommentsWithoutDetachedComments ( ) ;
}
else {
// get the leading comments from the node
leadingComments = getLeadingCommentRangesOfNode ( node , currentSourceFile ) ;
}
return leadingComments ;
2014-07-17 00:39:14 +02:00
}
}
}
2014-08-07 02:58:03 +02:00
2014-10-11 01:44:14 +02:00
function emitLeadingDeclarationComments ( node : Node ) {
var leadingComments = getLeadingCommentsToEmit ( node ) ;
2014-10-13 19:53:57 +02:00
emitNewLineBeforeLeadingComments ( currentSourceFile , writer , node , leadingComments ) ;
2014-10-11 01:44:14 +02:00
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2014-10-13 19:53:57 +02:00
emitComments ( currentSourceFile , writer , leadingComments , /*trailingSeparator*/ true , newLine , writeComment ) ;
2014-07-13 01:04:16 +02:00
}
2014-08-07 02:58:03 +02:00
2014-10-11 01:44:14 +02:00
function emitTrailingDeclarationComments ( node : Node ) {
// Emit the trailing comments only if the parent's end doesn't match
2015-01-23 00:58:00 +01:00
if ( node . parent ) {
if ( node . parent . kind === SyntaxKind . SourceFile || node . end !== node . parent . end ) {
var trailingComments = getTrailingCommentRanges ( currentSourceFile . text , node . end ) ;
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
emitComments ( currentSourceFile , writer , trailingComments , /*trailingSeparator*/ false , newLine , writeComment ) ;
}
2014-08-07 02:58:03 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function emitLeadingCommentsOfLocalPosition ( pos : number ) {
var leadingComments : CommentRange [ ] ;
if ( hasDetachedComments ( pos ) ) {
// get comments without detached comments
leadingComments = getLeadingCommentsWithoutDetachedComments ( ) ;
2014-12-03 00:52:29 +01:00
}
else {
2014-10-11 01:44:14 +02:00
// get the leading comments from the node
leadingComments = getLeadingCommentRanges ( currentSourceFile . text , pos ) ;
2014-07-17 00:39:14 +02:00
}
2014-10-13 19:53:57 +02:00
emitNewLineBeforeLeadingComments ( currentSourceFile , writer , { pos : pos , end : pos } , leadingComments ) ;
2014-10-11 01:44:14 +02:00
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2014-10-13 19:53:57 +02:00
emitComments ( currentSourceFile , writer , leadingComments , /*trailingSeparator*/ true , newLine , writeComment ) ;
2014-10-11 01:44:14 +02:00
}
2014-07-13 01:04:16 +02:00
2014-10-11 01:44:14 +02:00
function emitDetachedCommentsAtPosition ( node : TextRange ) {
var leadingComments = getLeadingCommentRanges ( currentSourceFile . text , node . pos ) ;
if ( leadingComments ) {
var detachedComments : CommentRange [ ] = [ ] ;
var lastComment : CommentRange ;
2014-08-07 02:06:59 +02:00
2014-10-11 01:44:14 +02:00
forEach ( leadingComments , comment = > {
if ( lastComment ) {
2014-10-13 19:53:57 +02:00
var lastCommentLine = getLineOfLocalPosition ( currentSourceFile , lastComment . end ) ;
var commentLine = getLineOfLocalPosition ( currentSourceFile , comment . pos ) ;
2014-08-07 02:06:59 +02:00
2014-10-11 01:44:14 +02:00
if ( commentLine >= lastCommentLine + 2 ) {
// There was a blank line between the last comment and this comment. This
// comment is not part of the copyright comments. Return what we have so
// far.
return detachedComments ;
}
}
2014-08-07 02:06:59 +02:00
2014-10-11 01:44:14 +02:00
detachedComments . push ( comment ) ;
lastComment = comment ;
} ) ;
2014-08-07 02:06:59 +02:00
2014-10-11 01:44:14 +02:00
if ( detachedComments . length ) {
// All comments look like they could have been part of the copyright header. Make
// sure there is at least one blank line between it and the node. If not, it's not
// a copyright header.
2014-10-13 19:53:57 +02:00
var lastCommentLine = getLineOfLocalPosition ( currentSourceFile , detachedComments [ detachedComments . length - 1 ] . end ) ;
var astLine = getLineOfLocalPosition ( currentSourceFile , skipTrivia ( currentSourceFile . text , node . pos ) ) ;
2014-10-11 01:44:14 +02:00
if ( astLine >= lastCommentLine + 2 ) {
// Valid detachedComments
2014-10-13 19:53:57 +02:00
emitNewLineBeforeLeadingComments ( currentSourceFile , writer , node , leadingComments ) ;
emitComments ( currentSourceFile , writer , detachedComments , /*trailingSeparator*/ true , newLine , writeComment ) ;
2014-10-11 01:44:14 +02:00
var currentDetachedCommentInfo = { nodePos : node.pos , detachedCommentEndPos : detachedComments [ detachedComments . length - 1 ] . end } ;
if ( detachedCommentsInfo ) {
detachedCommentsInfo . push ( currentDetachedCommentInfo ) ;
2014-08-07 02:06:59 +02:00
}
else {
2014-10-11 01:44:14 +02:00
detachedCommentsInfo = [ currentDetachedCommentInfo ] ;
2014-08-07 02:06:59 +02:00
}
2014-10-11 01:44:14 +02:00
}
2014-08-07 02:06:59 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-10-11 01:44:14 +02:00
function emitPinnedOrTripleSlashCommentsOfNode ( node : Node ) {
var pinnedComments = ts . filter ( getLeadingCommentsToEmit ( node ) , isPinnedOrTripleSlashComment ) ;
2014-08-07 02:06:59 +02:00
2014-10-11 01:44:14 +02:00
function isPinnedOrTripleSlashComment ( comment : CommentRange ) {
if ( currentSourceFile . text . charCodeAt ( comment . pos + 1 ) === CharacterCodes . asterisk ) {
return currentSourceFile . text . charCodeAt ( comment . pos + 2 ) === CharacterCodes . exclamation ;
}
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
// so that we don't end up computing comment string and doing match for all // comments
else if ( currentSourceFile . text . charCodeAt ( comment . pos + 1 ) === CharacterCodes . slash &&
comment . pos + 2 < comment . end &&
currentSourceFile . text . charCodeAt ( comment . pos + 2 ) === CharacterCodes . slash &&
currentSourceFile . text . substring ( comment . pos , comment . end ) . match ( fullTripleSlashReferencePathRegEx ) ) {
return true ;
2014-08-07 02:06:59 +02:00
}
2014-07-17 00:39:14 +02:00
}
2014-10-13 19:53:57 +02:00
emitNewLineBeforeLeadingComments ( currentSourceFile , writer , node , pinnedComments ) ;
2014-10-11 01:44:14 +02:00
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2014-10-13 19:53:57 +02:00
emitComments ( currentSourceFile , writer , pinnedComments , /*trailingSeparator*/ true , newLine , writeComment ) ;
2014-07-17 00:39:14 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-11-21 05:24:08 +01:00
function writeDeclarationFile ( jsFilePath : string , sourceFile : SourceFile ) {
2014-12-16 22:52:47 +01:00
var emitDeclarationResult = emitDeclarations ( host , resolver , diagnostics , jsFilePath , sourceFile ) ;
2014-07-19 03:06:37 +02:00
// 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
2014-11-21 05:24:08 +01:00
if ( ! emitDeclarationResult . reportedDeclarationError ) {
var declarationOutput = emitDeclarationResult . referencePathsOutput ;
2014-08-05 02:59:33 +02:00
// apply additions
var appliedSyncOutputPos = 0 ;
2014-11-21 05:24:08 +01:00
forEach ( emitDeclarationResult . aliasDeclarationEmitInfo , aliasEmitInfo = > {
2014-08-05 02:59:33 +02:00
if ( aliasEmitInfo . asynchronousOutput ) {
2014-11-21 05:24:08 +01:00
declarationOutput += emitDeclarationResult . synchronousDeclarationOutput . substring ( appliedSyncOutputPos , aliasEmitInfo . outputPos ) ;
2014-08-05 02:59:33 +02:00
declarationOutput += aliasEmitInfo . asynchronousOutput ;
appliedSyncOutputPos = aliasEmitInfo . outputPos ;
}
} ) ;
2014-11-21 05:24:08 +01:00
declarationOutput += emitDeclarationResult . synchronousDeclarationOutput . substring ( appliedSyncOutputPos ) ;
2014-12-16 23:42:58 +01:00
writeFile ( host , diagnostics , removeFileExtension ( jsFilePath ) + ".d.ts" , declarationOutput , compilerOptions . emitBOM ) ;
2014-07-19 03:06:37 +02:00
}
2014-07-13 01:04:16 +02:00
}
2014-09-12 21:57:00 +02:00
2014-12-02 08:15:13 +01:00
function emitFile ( jsFilePath : string , sourceFile? : SourceFile ) {
2015-02-05 23:41:04 +01:00
emitJavaScript ( jsFilePath , sourceFile ) ;
2014-12-02 08:15:13 +01:00
2015-02-05 23:41:04 +01:00
if ( compilerOptions . declaration ) {
writeDeclarationFile ( jsFilePath , sourceFile ) ;
2014-12-02 08:15:13 +01:00
}
2014-09-06 01:18:39 +02:00
}
2014-07-13 01:04:16 +02:00
}
}