2014-07-13 01:04:16 +02:00
|
|
|
/// <reference path="types.ts"/>
|
|
|
|
/// <reference path="core.ts"/>
|
|
|
|
/// <reference path="scanner.ts"/>
|
|
|
|
/// <reference path="parser.ts"/>
|
|
|
|
|
|
|
|
module ts {
|
2014-07-17 00:39:14 +02:00
|
|
|
interface EmitTextWriter extends TextWriter {
|
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
|
|
|
}
|
|
|
|
|
2014-08-14 23:43:28 +02:00
|
|
|
var indentStrings: string[] = ["", " "];
|
2014-07-17 00:39:14 +02:00
|
|
|
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-07-16 19:49:11 +02:00
|
|
|
export function emitFiles(resolver: EmitResolver): EmitResult {
|
2014-07-13 01:04:16 +02:00
|
|
|
var program = resolver.getProgram();
|
|
|
|
var compilerHost = program.getCompilerHost();
|
|
|
|
var compilerOptions = program.getCompilerOptions();
|
|
|
|
var sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined;
|
2014-07-16 19:49:11 +02:00
|
|
|
var diagnostics: Diagnostic[] = [];
|
2014-07-19 02:46:41 +02:00
|
|
|
var newLine = program.getCompilerHost().getNewLine();
|
2014-07-16 19:49:11 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function getSourceFilePathInNewDir(newDirPath: string, sourceFile: SourceFile) {
|
|
|
|
var sourceFilePath = getNormalizedPathFromPathCompoments(getNormalizedPathComponents(sourceFile.filename, compilerHost.getCurrentDirectory()));
|
|
|
|
sourceFilePath = sourceFilePath.replace(program.getCommonSourceDirectory(), "");
|
|
|
|
return combinePaths(newDirPath, sourceFilePath);
|
|
|
|
}
|
|
|
|
|
2014-07-17 21:53:07 +02:00
|
|
|
function shouldEmitToOwnFile(sourceFile: SourceFile) {
|
2014-07-17 00:39:14 +02:00
|
|
|
if (!(sourceFile.flags & NodeFlags.DeclarationFile)) {
|
2014-07-18 04:11:01 +02:00
|
|
|
if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.filename, ".js")) {
|
2014-07-17 00:39:14 +02:00
|
|
|
return true;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function getOwnEmitOutputFilePath(sourceFile: SourceFile, extension: string) {
|
|
|
|
if (program.getCompilerOptions().outDir) {
|
|
|
|
var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(getSourceFilePathInNewDir(program.getCompilerOptions().outDir, sourceFile));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(sourceFile.filename);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
|
|
|
return emitOutputFilePathWithoutExtension + extension;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) {
|
2014-07-18 04:11:01 +02:00
|
|
|
return isExternalModule(sourceFile) || (sourceFile.flags & NodeFlags.DeclarationFile) !== 0;
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function getFirstConstructorWithBody(node: ClassDeclaration): ConstructorDeclaration {
|
|
|
|
return forEach(node.members, member => {
|
|
|
|
if (member.kind === SyntaxKind.Constructor && (<ConstructorDeclaration>member).body) {
|
|
|
|
return <ConstructorDeclaration>member;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function getAllAccessorDeclarations(node: ClassDeclaration, accessor: AccessorDeclaration) {
|
|
|
|
var firstAccessor: AccessorDeclaration;
|
|
|
|
var getAccessor: AccessorDeclaration;
|
|
|
|
var setAccessor: AccessorDeclaration;
|
|
|
|
forEach(node.members, (member: Declaration) => {
|
|
|
|
if ((member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor) &&
|
|
|
|
member.name.text === accessor.name.text &&
|
|
|
|
(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
|
|
|
});
|
|
|
|
return {
|
|
|
|
firstAccessor: firstAccessor,
|
|
|
|
getAccessor: getAccessor,
|
|
|
|
setAccessor: setAccessor
|
|
|
|
};
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-18 23:40:47 +02:00
|
|
|
function createTextWriter(writeSymbol: (symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags)=> void): EmitTextWriter {
|
2014-07-17 00:39:14 +02:00
|
|
|
var output = "";
|
|
|
|
var indent = 0;
|
|
|
|
var lineStart = true;
|
|
|
|
var lineCount = 0;
|
|
|
|
var linePos = 0;
|
|
|
|
|
|
|
|
function write(s: string) {
|
|
|
|
if (s && s.length) {
|
|
|
|
if (lineStart) {
|
|
|
|
output += getIndentString(indent);
|
|
|
|
lineStart = false;
|
|
|
|
}
|
|
|
|
output += s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-16 01:58:38 +02:00
|
|
|
function rawWrite(s: string) {
|
|
|
|
if (s !== undefined) {
|
|
|
|
if (lineStart) {
|
|
|
|
lineStart = false;
|
|
|
|
}
|
|
|
|
output += s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function writeLiteral(s: string) {
|
|
|
|
if (s && s.length) {
|
|
|
|
write(s);
|
2014-08-30 02:20:05 +02:00
|
|
|
var lineStartsOfS = getLineStarts(s);
|
|
|
|
if (lineStartsOfS.length > 1) {
|
|
|
|
lineCount = lineCount + lineStartsOfS.length - 1;
|
2014-09-03 06:11:21 +02:00
|
|
|
linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1];
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function writeLine() {
|
|
|
|
if (!lineStart) {
|
2014-07-19 02:46:41 +02:00
|
|
|
output += newLine;
|
2014-07-17 00:39:14 +02:00
|
|
|
lineCount++;
|
|
|
|
linePos = output.length;
|
|
|
|
lineStart = true;
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
|
|
|
return {
|
|
|
|
write: write,
|
2014-07-18 23:40:47 +02:00
|
|
|
writeSymbol: writeSymbol,
|
2014-08-16 01:58:38 +02:00
|
|
|
rawWrite: rawWrite,
|
2014-07-17 00:39:14 +02:00
|
|
|
writeLiteral: writeLiteral,
|
|
|
|
writeLine: writeLine,
|
|
|
|
increaseIndent: () => indent++,
|
|
|
|
decreaseIndent: () => indent--,
|
2014-08-05 02:59:33 +02:00
|
|
|
getIndent: () => indent,
|
2014-07-17 00:39:14 +02:00
|
|
|
getTextPos: () => output.length,
|
|
|
|
getLine: () => lineCount + 1,
|
2014-08-16 01:58:38 +02:00
|
|
|
getColumn: () => lineStart ? indent * getIndentSize() + 1 : output.length - linePos + 1,
|
2014-08-12 00:54:12 +02:00
|
|
|
getText: () => output,
|
2014-07-17 00:39:14 +02:00
|
|
|
};
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// Get source text of node in the current source file. Unlike getSourceTextOfNode this function
|
|
|
|
// doesn't walk the parent chain to find the containing source file, rather it assumes the node is
|
|
|
|
// in the source file currently being processed.
|
|
|
|
var currentSourceFile: SourceFile;
|
|
|
|
function getSourceTextOfLocalNode(node: Node): string {
|
|
|
|
var text = currentSourceFile.text;
|
|
|
|
return text.substring(skipTrivia(text, node.pos), node.end);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-08-21 01:50:28 +02:00
|
|
|
function getLineOfLocalPosition(pos: number) {
|
|
|
|
return currentSourceFile.getLineAndCharacterFromPosition(pos).line;
|
|
|
|
}
|
|
|
|
|
2014-08-06 20:32:51 +02:00
|
|
|
function writeFile(filename: string, data: string, writeByteOrderMark: boolean) {
|
|
|
|
compilerHost.writeFile(filename, data, writeByteOrderMark, hostErrorMessage => {
|
2014-07-17 00:39:14 +02:00
|
|
|
diagnostics.push(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, filename, hostErrorMessage));
|
|
|
|
});
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-08-15 23:32:08 +02:00
|
|
|
function emitComments(comments: Comment[], trailingSeparator: boolean, writer: EmitTextWriter, writeComment: (comment: Comment, writer: EmitTextWriter) => void) {
|
|
|
|
var emitLeadingSpace = !trailingSeparator;
|
2014-08-14 16:48:14 +02:00
|
|
|
forEach(comments, comment => {
|
2014-08-15 23:32:08 +02:00
|
|
|
if (emitLeadingSpace) {
|
|
|
|
writer.write(" ");
|
|
|
|
emitLeadingSpace = false;
|
|
|
|
}
|
2014-08-14 16:48:14 +02:00
|
|
|
writeComment(comment, writer);
|
|
|
|
if (comment.hasTrailingNewLine) {
|
|
|
|
writer.writeLine();
|
2014-08-21 01:50:28 +02:00
|
|
|
}
|
|
|
|
else if (trailingSeparator) {
|
2014-08-14 16:48:14 +02:00
|
|
|
writer.write(" ");
|
|
|
|
}
|
2014-08-15 23:32:08 +02:00
|
|
|
else {
|
|
|
|
// Emit leading space to separate comment during next comment emit
|
|
|
|
emitLeadingSpace = true;
|
|
|
|
}
|
2014-08-14 16:48:14 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-08-19 21:06:52 +02:00
|
|
|
function emitNewLineBeforeLeadingComments(node: TextRange, leadingComments: Comment[], writer: EmitTextWriter) {
|
2014-08-15 23:21:41 +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-08-21 01:50:28 +02:00
|
|
|
getLineOfLocalPosition(node.pos) !== getLineOfLocalPosition(leadingComments[0].pos)) {
|
2014-08-15 23:21:41 +02:00
|
|
|
writer.writeLine();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-14 16:48:14 +02:00
|
|
|
function writeCommentRange(comment: Comment, writer: EmitTextWriter) {
|
2014-08-14 23:43:28 +02:00
|
|
|
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
|
|
|
|
var firstCommentLineAndCharacter = currentSourceFile.getLineAndCharacterFromPosition(comment.pos);
|
|
|
|
var firstCommentLineIndent: number;
|
|
|
|
for (var pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) {
|
|
|
|
var nextLineStart = currentSourceFile.getPositionFromLineAndCharacter(currentLine + 1, /*character*/1);
|
|
|
|
|
|
|
|
if (pos !== comment.pos) {
|
2014-08-16 01:58:38 +02:00
|
|
|
// If we are not emitting first line, we need to write the spaces to adjust the alignment
|
2014-08-14 23:43:28 +02:00
|
|
|
if (firstCommentLineIndent === undefined) {
|
|
|
|
firstCommentLineIndent = calculateIndent(currentSourceFile.getPositionFromLineAndCharacter(firstCommentLineAndCharacter.line, /*character*/1),
|
|
|
|
comment.pos);
|
|
|
|
}
|
2014-08-15 23:43:22 +02:00
|
|
|
|
2014-08-16 01:58:38 +02:00
|
|
|
// 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--;
|
2014-08-14 23:43:28 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-16 01:58:38 +02:00
|
|
|
else {
|
|
|
|
// No spaces to emit write empty string
|
|
|
|
writer.rawWrite("");
|
|
|
|
}
|
2014-08-14 23:43:28 +02:00
|
|
|
}
|
|
|
|
|
2014-08-16 01:58:38 +02:00
|
|
|
// Write the comment line text
|
|
|
|
writeTrimmedCurrentLine(pos, nextLineStart);
|
|
|
|
|
2014-08-14 23:43:28 +02:00
|
|
|
pos = nextLineStart;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Single line comment of styly //....
|
|
|
|
writer.write(currentSourceFile.text.substring(comment.pos, comment.end));
|
|
|
|
}
|
|
|
|
|
|
|
|
function writeTrimmedCurrentLine(pos: number, nextLineStart: number) {
|
2014-08-16 01:58:38 +02:00
|
|
|
var end = Math.min(comment.end, nextLineStart - 1);
|
|
|
|
var currentLineText = currentSourceFile.text.substring(pos, end).replace(/^\s+|\s+$/g, '');
|
2014-08-14 23:43:28 +02:00
|
|
|
if (currentLineText) {
|
|
|
|
// trimmed forward and ending spaces text
|
|
|
|
writer.write(currentLineText);
|
2014-08-16 01:58:38 +02:00
|
|
|
if (end !== comment.end) {
|
|
|
|
writer.writeLine();
|
|
|
|
}
|
2014-08-14 23:43:28 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Empty string - make sure we write empty line
|
2014-08-29 08:10:05 +02:00
|
|
|
writer.writeLiteral(newLine);
|
2014-08-14 23:43:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function calculateIndent(pos: number, end: number) {
|
|
|
|
var currentLineIndent = 0;
|
|
|
|
while (pos < end && isWhiteSpace(currentSourceFile.text.charCodeAt(pos))) {
|
|
|
|
pos++;
|
|
|
|
if (currentSourceFile.text.charCodeAt(pos) === CharacterCodes.tab) {
|
|
|
|
// Tabs = size of the indent
|
|
|
|
currentLineIndent += getIndentSize();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Single space
|
|
|
|
currentLineIndent++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return currentLineIndent;
|
|
|
|
}
|
2014-08-14 16:48:14 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
|
2014-07-18 23:40:47 +02:00
|
|
|
var writer = createTextWriter(writeSymbol);
|
2014-07-17 00:39:14 +02:00
|
|
|
var write = writer.write;
|
|
|
|
var writeLine = writer.writeLine;
|
|
|
|
var increaseIndent = writer.increaseIndent;
|
|
|
|
var decreaseIndent = writer.decreaseIndent;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
var extendsEmitted = false;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
/** write emitted output to disk*/
|
|
|
|
var writeEmittedFiles = writeJavaScriptFile;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-08-19 19:43:13 +02:00
|
|
|
/** Emit leading comments of the node */
|
|
|
|
var emitLeadingComments = compilerOptions.removeComments ? (node: Node) => { } : emitLeadingDeclarationComments;
|
2014-08-12 00:54:12 +02:00
|
|
|
|
2014-08-19 19:43:13 +02:00
|
|
|
/** Emit Trailing comments of the node */
|
|
|
|
var emitTrailingComments = compilerOptions.removeComments ? (node: Node) => { } : emitTrailingDeclarationComments;
|
|
|
|
|
2014-08-22 02:17:02 +02:00
|
|
|
var emitLeadingCommentsOfPosition = compilerOptions.removeComments ? (pos: number) => { } : emitLeadingCommentsOfLocalPosition;
|
|
|
|
|
2014-08-19 21:06:52 +02:00
|
|
|
var detachedCommentsInfo: { nodePos: number; detachedCommentEndPos: number }[];
|
2014-08-19 19:43:13 +02:00
|
|
|
/** Emit detached comments of the node */
|
2014-08-19 21:06:52 +02:00
|
|
|
var emitDetachedComments = compilerOptions.removeComments ? (node: TextRange) => { } : emitDetachedCommentsAtPosition;
|
2014-08-12 00:54:12 +02:00
|
|
|
|
2014-08-22 23:40:47 +02:00
|
|
|
/** Emits /// or pinned which is comment starting with /*! comments */
|
|
|
|
var emitPinnedOrTripleSlashComments = compilerOptions.removeComments ? (node: Node) => { } : emitPinnedOrTripleSlashCommentsOfNode;
|
|
|
|
|
2014-08-12 00:54:12 +02:00
|
|
|
var writeComment = writeCommentRange;
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
/** Emit a node */
|
|
|
|
var emit = emitNode;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
/** Called just before starting emit of a node */
|
2014-08-12 00:54:12 +02:00
|
|
|
var emitStart = function (node: Node) { };
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
/** Called once the emit of the node is done */
|
2014-08-12 00:54:12 +02:00
|
|
|
var emitEnd = function (node: Node) { };
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
/** Emit the text for the given token that comes after startPos
|
|
|
|
* 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-07-17 00:39:14 +02:00
|
|
|
/** Called to before starting the lexical scopes as in function/class in the emitted code because of node
|
|
|
|
* @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-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
/** Called after coming out of the scope */
|
|
|
|
var scopeEmitEnd = function () { }
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
/** Sourcemap data that will get encoded */
|
|
|
|
var sourceMapData: SourceMapData;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-18 23:40:47 +02:00
|
|
|
function writeSymbol(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags) { }
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function initializeEmitterWithSourceMaps() {
|
|
|
|
var sourceMapDir: string; // The directory in which sourcemap will be
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// Current source map file and its index in the sources list
|
|
|
|
var sourceMapSourceIndex = -1;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// Names and its index map
|
|
|
|
var sourceMapNameIndexMap: Map<number> = {};
|
|
|
|
var sourceMapNameIndices: number[] = [];
|
|
|
|
function getSourceMapNameIndex() {
|
|
|
|
return sourceMapNameIndices.length ? sourceMapNameIndices[sourceMapNameIndices.length - 1] : -1;
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39: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;
|
|
|
|
|
|
|
|
// Encoding for sourcemap span
|
|
|
|
function encodeLastRecordedSourceMapSpan() {
|
|
|
|
if (!lastRecordedSourceMapSpan || lastRecordedSourceMapSpan === lastEncodedSourceMapSpan) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var prevEncodedEmittedColumn = lastEncodedSourceMapSpan.emittedColumn;
|
|
|
|
// Line/Comma deliminators
|
|
|
|
if (lastEncodedSourceMapSpan.emittedLine == lastRecordedSourceMapSpan.emittedLine) {
|
|
|
|
// Emit comma to separate the entry
|
|
|
|
if (sourceMapData.sourceMapMappings) {
|
|
|
|
sourceMapData.sourceMapMappings += ",";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Emit line deliminators
|
|
|
|
for (var encodedLine = lastEncodedSourceMapSpan.emittedLine; encodedLine < lastRecordedSourceMapSpan.emittedLine; encodedLine++) {
|
|
|
|
sourceMapData.sourceMapMappings += ";";
|
|
|
|
}
|
|
|
|
prevEncodedEmittedColumn = 1;
|
|
|
|
}
|
2014-07-16 19:49:11 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// 1. Relative Column 0 based
|
|
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.emittedColumn - prevEncodedEmittedColumn);
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// 2. Relative sourceIndex
|
|
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceIndex - lastEncodedSourceMapSpan.sourceIndex);
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// 3. Relative sourceLine 0 based
|
|
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceLine - lastEncodedSourceMapSpan.sourceLine);
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// 4. Relative sourceColumn 0 based
|
|
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceColumn - lastEncodedSourceMapSpan.sourceColumn);
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// 5. Relative namePosition 0 based
|
|
|
|
if (lastRecordedSourceMapSpan.nameIndex >= 0) {
|
|
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.nameIndex - lastEncodedNameIndex);
|
|
|
|
lastEncodedNameIndex = lastRecordedSourceMapSpan.nameIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
lastEncodedSourceMapSpan = lastRecordedSourceMapSpan;
|
|
|
|
sourceMapData.sourceMapDecodedMappings.push(lastEncodedSourceMapSpan);
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39: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");
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
inValue = inValue << 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
return encodedStr;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
|
|
|
function recordSourceMapSpan(pos: number) {
|
|
|
|
var sourceLinePos = currentSourceFile.getLineAndCharacterFromPosition(pos);
|
|
|
|
var emittedLine = writer.getLine();
|
|
|
|
var emittedColumn = writer.getColumn();
|
|
|
|
|
|
|
|
// If this location wasnt recorded or the location in source is going backwards, record the span
|
|
|
|
if (!lastRecordedSourceMapSpan ||
|
|
|
|
lastRecordedSourceMapSpan.emittedLine != emittedLine ||
|
|
|
|
lastRecordedSourceMapSpan.emittedColumn != emittedColumn ||
|
2014-08-20 04:49:03 +02:00
|
|
|
(lastRecordedSourceMapSpan.sourceIndex === sourceMapSourceIndex &&
|
|
|
|
(lastRecordedSourceMapSpan.sourceLine > sourceLinePos.line ||
|
|
|
|
(lastRecordedSourceMapSpan.sourceLine === sourceLinePos.line && lastRecordedSourceMapSpan.sourceColumn > sourceLinePos.character)))) {
|
2014-07-17 00:39:14 +02:00
|
|
|
// Encode the last recordedSpan before assigning new
|
|
|
|
encodeLastRecordedSourceMapSpan();
|
|
|
|
|
|
|
|
// New span
|
|
|
|
lastRecordedSourceMapSpan = {
|
|
|
|
emittedLine: emittedLine,
|
|
|
|
emittedColumn: emittedColumn,
|
|
|
|
sourceLine: sourceLinePos.line,
|
|
|
|
sourceColumn: sourceLinePos.character,
|
|
|
|
nameIndex: getSourceMapNameIndex(),
|
|
|
|
sourceIndex: sourceMapSourceIndex
|
|
|
|
};
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// 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;
|
2014-08-20 04:49:03 +02:00
|
|
|
lastRecordedSourceMapSpan.sourceIndex = sourceMapSourceIndex;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function recordEmitNodeStartSpan(node: Node) {
|
|
|
|
// Get the token pos after skipping to the token (ignoring the leading trivia)
|
2014-08-20 05:33:36 +02:00
|
|
|
recordSourceMapSpan(skipTrivia(currentSourceFile.text, node.pos));
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function recordEmitNodeEndSpan(node: Node) {
|
|
|
|
recordSourceMapSpan(node.end);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39: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-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function recordNewSourceFileStart(node: SourceFile) {
|
|
|
|
// Add the 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
|
|
|
|
var sourcesDirectoryPath = compilerOptions.sourceRoot ? program.getCommonSourceDirectory() : sourceMapDir;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
sourceMapData.sourceMapSources.push(getRelativePathToDirectoryOrUrl(sourcesDirectoryPath,
|
|
|
|
node.filename,
|
|
|
|
compilerHost.getCurrentDirectory(),
|
|
|
|
/*isAbsolutePathAnUrl*/ true));
|
|
|
|
sourceMapSourceIndex = sourceMapData.sourceMapSources.length - 1;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// The one that can be used from program to get the actual source file
|
|
|
|
sourceMapData.inputSourceFileNames.push(node.filename);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function recordScopeNameOfNode(node: Node, scopeName?: string) {
|
|
|
|
function recordScopeNameIndex(scopeNameIndex: number) {
|
|
|
|
sourceMapNameIndices.push(scopeNameIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
function recordScopeNameStart(scopeName: string) {
|
|
|
|
var scopeNameIndex = -1;
|
|
|
|
if (scopeName) {
|
|
|
|
var parentIndex = getSourceMapNameIndex();
|
|
|
|
if (parentIndex !== -1) {
|
|
|
|
scopeName = sourceMapData.sourceMapNames[parentIndex] + "." + scopeName;
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
scopeNameIndex = getProperty(sourceMapNameIndexMap, scopeName);
|
|
|
|
if (scopeNameIndex === undefined) {
|
|
|
|
scopeNameIndex = sourceMapData.sourceMapNames.length;
|
|
|
|
sourceMapData.sourceMapNames.push(scopeName);
|
|
|
|
sourceMapNameIndexMap[scopeName] = scopeNameIndex;
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
recordScopeNameIndex(scopeNameIndex);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (scopeName) {
|
|
|
|
// The scope was already given a name use it
|
|
|
|
recordScopeNameStart(scopeName);
|
|
|
|
}
|
|
|
|
else if (node.kind === SyntaxKind.FunctionDeclaration ||
|
|
|
|
node.kind === SyntaxKind.FunctionExpression ||
|
|
|
|
node.kind === SyntaxKind.Method ||
|
|
|
|
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) {
|
|
|
|
scopeName = (<Declaration>node).name.text;
|
|
|
|
}
|
|
|
|
recordScopeNameStart(scopeName);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
// Block just use the name from upper level scope
|
|
|
|
recordScopeNameIndex(getSourceMapNameIndex());
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function recordScopeNameEnd() {
|
|
|
|
sourceMapNameIndices.pop();
|
|
|
|
};
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-08-14 16:48:14 +02:00
|
|
|
function writeCommentRangeWithMap(comment: Comment, writer: EmitTextWriter) {
|
2014-08-12 00:54:12 +02:00
|
|
|
recordSourceMapSpan(comment.pos);
|
2014-08-14 16:48:14 +02:00
|
|
|
writeCommentRange(comment, writer);
|
2014-08-12 00:54:12 +02:00
|
|
|
recordSourceMapSpan(comment.end);
|
|
|
|
}
|
|
|
|
|
2014-08-06 20:32:51 +02:00
|
|
|
function writeJavaScriptAndSourceMapFile(emitOutput: string, writeByteOrderMark: boolean) {
|
2014-07-17 00:39:14 +02:00
|
|
|
// Write source map file
|
2014-07-13 01:04:16 +02:00
|
|
|
encodeLastRecordedSourceMapSpan();
|
2014-07-17 00:39:14 +02:00
|
|
|
writeFile(sourceMapData.sourceMapFilePath, JSON.stringify({
|
|
|
|
version: 3,
|
|
|
|
file: sourceMapData.sourceMapFile,
|
|
|
|
sourceRoot: sourceMapData.sourceMapSourceRoot,
|
|
|
|
sources: sourceMapData.sourceMapSources,
|
|
|
|
names: sourceMapData.sourceMapNames,
|
|
|
|
mappings: sourceMapData.sourceMapMappings
|
2014-08-06 20:32:51 +02:00
|
|
|
}), /*writeByteOrderMark*/ false);
|
2014-07-17 00:39:14 +02:00
|
|
|
sourceMapDataList.push(sourceMapData);
|
|
|
|
|
|
|
|
// Write sourcemap url to the js file and write the js file
|
2014-08-06 20:32:51 +02:00
|
|
|
writeJavaScriptFile(emitOutput + "//# sourceMappingURL=" + sourceMapData.jsSourceMappingURL, writeByteOrderMark);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize source map data
|
|
|
|
var sourceMapJsFile = getBaseFilename(normalizeSlashes(jsFilePath));
|
|
|
|
sourceMapData = {
|
|
|
|
sourceMapFilePath: jsFilePath + ".map",
|
|
|
|
jsSourceMappingURL: sourceMapJsFile + ".map",
|
|
|
|
sourceMapFile: sourceMapJsFile,
|
|
|
|
sourceMapSourceRoot: compilerOptions.sourceRoot || "",
|
|
|
|
sourceMapSources: [],
|
|
|
|
inputSourceFileNames: [],
|
|
|
|
sourceMapNames: [],
|
|
|
|
sourceMapMappings: "",
|
|
|
|
sourceMapDecodedMappings: []
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
sourceMapDir = getDirectoryPath(getSourceFilePathInNewDir(sourceMapDir, root));
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (!isRootedDiskPath(sourceMapDir) && !isUrl(sourceMapDir)) {
|
|
|
|
// The relative paths are relative to the common directory
|
|
|
|
sourceMapDir = combinePaths(program.getCommonSourceDirectory(), sourceMapDir);
|
|
|
|
sourceMapData.jsSourceMappingURL = getRelativePathToDirectoryOrUrl(
|
|
|
|
getDirectoryPath(normalizePath(jsFilePath)), // get the relative sourceMapDir path based on jsFilePath
|
|
|
|
combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL), // this is where user expects to see sourceMap
|
|
|
|
compilerHost.getCurrentDirectory(),
|
|
|
|
/*isAbsolutePathAnUrl*/ true);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sourceMapData.jsSourceMappingURL = combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
sourceMapDir = getDirectoryPath(normalizePath(jsFilePath));
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39: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-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
writeEmittedFiles = writeJavaScriptAndSourceMapFile;
|
|
|
|
emit = emitNodeWithMap;
|
|
|
|
emitStart = recordEmitNodeStartSpan;
|
|
|
|
emitEnd = recordEmitNodeEndSpan;
|
|
|
|
emitToken = writeTextWithSpanRecord;
|
|
|
|
scopeEmitStart = recordScopeNameOfNode;
|
|
|
|
scopeEmitEnd = recordScopeNameEnd;
|
2014-08-12 00:54:12 +02:00
|
|
|
writeComment = writeCommentRangeWithMap;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-08-06 20:32:51 +02:00
|
|
|
function writeJavaScriptFile(emitOutput: string, writeByteOrderMark: boolean) {
|
|
|
|
writeFile(jsFilePath, emitOutput, writeByteOrderMark);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitTokenText(tokenKind: SyntaxKind, startPos: number, emitFn?: () => void) {
|
|
|
|
var tokenString = tokenToString(tokenKind);
|
|
|
|
if (emitFn) {
|
|
|
|
emitFn();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write(tokenString);
|
|
|
|
}
|
|
|
|
return startPos + tokenString.length;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitOptional(prefix: string, node: Node) {
|
|
|
|
if (node) {
|
|
|
|
write(prefix);
|
|
|
|
emit(node);
|
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-07-17 00:39:14 +02:00
|
|
|
function emitCommaList(nodes: Node[], count?: number) {
|
|
|
|
if (!(count >= 0)) count = nodes.length;
|
|
|
|
if (nodes) {
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
|
|
if (i) write(", ");
|
|
|
|
emit(nodes[i]);
|
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-07-17 00:39:14 +02:00
|
|
|
function emitMultiLineList(nodes: Node[]) {
|
|
|
|
if (nodes) {
|
|
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
|
|
if (i) write(",");
|
|
|
|
writeLine();
|
|
|
|
emit(nodes[i]);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitLines(nodes: Node[]) {
|
2014-07-18 02:43:48 +02:00
|
|
|
emitLinesStartingAt(nodes, /*startIndex*/ 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
function emitLinesStartingAt(nodes: Node[], startIndex: number): void {
|
|
|
|
for (var i = startIndex; i < nodes.length; i++) {
|
2014-07-17 00:39:14 +02:00
|
|
|
writeLine();
|
|
|
|
emit(nodes[i]);
|
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-07-17 00:39:14 +02:00
|
|
|
function emitLiteral(node: LiteralExpression) {
|
|
|
|
var text = getSourceTextOfLocalNode(node);
|
|
|
|
if (node.kind === SyntaxKind.StringLiteral && compilerOptions.sourceMap) {
|
|
|
|
writer.writeLiteral(text);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
write(text);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39: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.
|
|
|
|
function emitQuotedIdentifier(node: Identifier) {
|
|
|
|
if (node.kind === SyntaxKind.StringLiteral) {
|
|
|
|
emitLiteral(node);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("\"");
|
|
|
|
|
|
|
|
if (node.kind === SyntaxKind.NumericLiteral) {
|
|
|
|
write(node.text);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
write(getSourceTextOfLocalNode(node));
|
|
|
|
}
|
|
|
|
|
|
|
|
write("\"");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function isNonExpressionIdentifier(node: Identifier) {
|
|
|
|
var parent = node.parent;
|
|
|
|
switch (parent.kind) {
|
|
|
|
case SyntaxKind.Parameter:
|
|
|
|
case SyntaxKind.VariableDeclaration:
|
|
|
|
case SyntaxKind.Property:
|
|
|
|
case SyntaxKind.PropertyAssignment:
|
|
|
|
case SyntaxKind.EnumMember:
|
|
|
|
case SyntaxKind.Method:
|
|
|
|
case SyntaxKind.FunctionDeclaration:
|
|
|
|
case SyntaxKind.GetAccessor:
|
|
|
|
case SyntaxKind.SetAccessor:
|
|
|
|
case SyntaxKind.FunctionExpression:
|
|
|
|
case SyntaxKind.ClassDeclaration:
|
|
|
|
case SyntaxKind.InterfaceDeclaration:
|
|
|
|
case SyntaxKind.EnumDeclaration:
|
|
|
|
case SyntaxKind.ModuleDeclaration:
|
|
|
|
case SyntaxKind.ImportDeclaration:
|
|
|
|
return (<Declaration>parent).name === node;
|
|
|
|
case SyntaxKind.BreakStatement:
|
|
|
|
case SyntaxKind.ContinueStatement:
|
|
|
|
case SyntaxKind.ExportAssignment:
|
|
|
|
return false;
|
|
|
|
case SyntaxKind.LabelledStatement:
|
|
|
|
return (<LabelledStatement>node.parent).label === node;
|
|
|
|
case SyntaxKind.CatchBlock:
|
|
|
|
return (<CatchBlock>node.parent).variable === node;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function emitIdentifier(node: Identifier) {
|
|
|
|
if (!isNonExpressionIdentifier(node)) {
|
|
|
|
var prefix = resolver.getExpressionNamePrefix(node);
|
|
|
|
if (prefix) {
|
|
|
|
write(prefix);
|
|
|
|
write(".");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
write(getSourceTextOfLocalNode(node));
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitThis(node: Node) {
|
|
|
|
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalThis) {
|
|
|
|
write("_this");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("this");
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitSuper(node: Node) {
|
|
|
|
var flags = resolver.getNodeCheckFlags(node);
|
|
|
|
if (flags & NodeCheckFlags.SuperInstance) {
|
|
|
|
write("_super.prototype");
|
|
|
|
}
|
|
|
|
else if (flags & NodeCheckFlags.SuperStatic) {
|
|
|
|
write("_super");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("super");
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitArrayLiteral(node: ArrayLiteral) {
|
|
|
|
if (node.flags & NodeFlags.MultiLine) {
|
|
|
|
write("[");
|
|
|
|
increaseIndent();
|
|
|
|
emitMultiLineList(node.elements);
|
|
|
|
decreaseIndent();
|
|
|
|
writeLine();
|
|
|
|
write("]");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("[");
|
|
|
|
emitCommaList(node.elements);
|
|
|
|
write("]");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitObjectLiteral(node: ObjectLiteral) {
|
|
|
|
if (!node.properties.length) {
|
|
|
|
write("{}");
|
|
|
|
}
|
|
|
|
else if (node.flags & NodeFlags.MultiLine) {
|
|
|
|
write("{");
|
|
|
|
increaseIndent();
|
|
|
|
emitMultiLineList(node.properties);
|
|
|
|
decreaseIndent();
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
write("}");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("{ ");
|
|
|
|
emitCommaList(node.properties);
|
|
|
|
write(" }");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitPropertyAssignment(node: PropertyDeclaration) {
|
2014-08-14 14:57:24 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emit(node.name);
|
|
|
|
write(": ");
|
|
|
|
emit(node.initializer);
|
2014-08-14 14:57:24 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitPropertyAccess(node: PropertyAccess) {
|
|
|
|
var text = resolver.getPropertyAccessSubstitution(node);
|
|
|
|
if (text) {
|
|
|
|
write(text);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
emit(node.left);
|
|
|
|
write(".");
|
|
|
|
emit(node.right);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitIndexedAccess(node: IndexedAccess) {
|
|
|
|
emit(node.object);
|
|
|
|
write("[");
|
|
|
|
emit(node.index);
|
|
|
|
write("]");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitCallExpression(node: CallExpression) {
|
|
|
|
var superCall = false;
|
|
|
|
if (node.func.kind === SyntaxKind.SuperKeyword) {
|
|
|
|
write("_super");
|
|
|
|
superCall = true;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
emit(node.func);
|
|
|
|
superCall = node.func.kind === SyntaxKind.PropertyAccess && (<PropertyAccess>node.func).left.kind === SyntaxKind.SuperKeyword;
|
|
|
|
}
|
|
|
|
if (superCall) {
|
|
|
|
write(".call(");
|
|
|
|
emitThis(node.func);
|
|
|
|
if (node.arguments.length) {
|
|
|
|
write(", ");
|
|
|
|
emitCommaList(node.arguments);
|
|
|
|
}
|
|
|
|
write(")");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("(");
|
|
|
|
emitCommaList(node.arguments);
|
|
|
|
write(")");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitNewExpression(node: NewExpression) {
|
|
|
|
write("new ");
|
|
|
|
emit(node.func);
|
|
|
|
if (node.arguments) {
|
|
|
|
write("(");
|
|
|
|
emitCommaList(node.arguments);
|
|
|
|
write(")");
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitParenExpression(node: ParenExpression) {
|
|
|
|
if (node.expression.kind === SyntaxKind.TypeAssertion) {
|
|
|
|
var operand = (<TypeAssertion>node.expression).operand;
|
|
|
|
|
|
|
|
// Make sure we consider all nested cast expressions, e.g.:
|
|
|
|
// (<any><number><any>-A).x;
|
|
|
|
while (operand.kind == SyntaxKind.TypeAssertion) {
|
|
|
|
operand = (<TypeAssertion>operand).operand;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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(){} ()
|
|
|
|
if (operand.kind !== SyntaxKind.PrefixOperator && operand.kind !== SyntaxKind.PostfixOperator && operand.kind !== SyntaxKind.NewExpression &&
|
|
|
|
!(operand.kind === SyntaxKind.CallExpression && node.parent.kind === SyntaxKind.NewExpression) &&
|
|
|
|
!(operand.kind === SyntaxKind.FunctionExpression && node.parent.kind === SyntaxKind.CallExpression)) {
|
|
|
|
emit(operand);
|
|
|
|
return;
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
write("(");
|
|
|
|
emit(node.expression);
|
|
|
|
write(")");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitUnaryExpression(node: UnaryExpression) {
|
|
|
|
if (node.kind === SyntaxKind.PrefixOperator) {
|
|
|
|
write(tokenToString(node.operator));
|
|
|
|
}
|
|
|
|
// In some cases, we need to emit a space between the operator and the operand. One obvious case
|
|
|
|
// is when the operator is an identifer, 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.
|
|
|
|
if (node.operator >= SyntaxKind.Identifier) {
|
|
|
|
write(" ");
|
|
|
|
}
|
|
|
|
else if (node.kind === SyntaxKind.PrefixOperator && node.operand.kind === SyntaxKind.PrefixOperator) {
|
|
|
|
var operand = <UnaryExpression>node.operand;
|
|
|
|
if (node.operator === SyntaxKind.PlusToken && (operand.operator === SyntaxKind.PlusToken || operand.operator === SyntaxKind.PlusPlusToken)) {
|
|
|
|
write(" ");
|
|
|
|
}
|
|
|
|
else if (node.operator === SyntaxKind.MinusToken && (operand.operator === SyntaxKind.MinusToken || operand.operator === SyntaxKind.MinusMinusToken)) {
|
|
|
|
write(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
emit(node.operand);
|
|
|
|
if (node.kind === SyntaxKind.PostfixOperator) {
|
|
|
|
write(tokenToString(node.operator));
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitBinaryExpression(node: BinaryExpression) {
|
|
|
|
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-07-17 00:39:14 +02:00
|
|
|
function emitConditionalExpression(node: ConditionalExpression) {
|
|
|
|
emit(node.condition);
|
|
|
|
write(" ? ");
|
|
|
|
emit(node.whenTrue);
|
|
|
|
write(" : ");
|
|
|
|
emit(node.whenFalse);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitBlock(node: Block) {
|
|
|
|
emitToken(SyntaxKind.OpenBraceToken, node.pos);
|
2014-07-13 01:04:16 +02:00
|
|
|
increaseIndent();
|
2014-07-17 00:39:14 +02:00
|
|
|
scopeEmitStart(node.parent);
|
|
|
|
if (node.kind === SyntaxKind.ModuleBlock) {
|
|
|
|
Debug.assert(node.parent.kind === SyntaxKind.ModuleDeclaration);
|
|
|
|
emitCaptureThisForNodeIfNecessary(node.parent);
|
|
|
|
}
|
|
|
|
emitLines(node.statements);
|
2014-07-13 01:04:16 +02:00
|
|
|
decreaseIndent();
|
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitToken(SyntaxKind.CloseBraceToken, node.statements.end);
|
|
|
|
scopeEmitEnd();
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitEmbeddedStatement(node: Node) {
|
|
|
|
if (node.kind === SyntaxKind.Block) {
|
|
|
|
write(" ");
|
|
|
|
emit(<Block>node);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
increaseIndent();
|
|
|
|
writeLine();
|
|
|
|
emit(node);
|
|
|
|
decreaseIndent();
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
|
|
|
function emitExpressionStatement(node: ExpressionStatement) {
|
|
|
|
var isArrowExpression = node.expression.kind === SyntaxKind.ArrowFunction;
|
2014-08-16 00:49:09 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (isArrowExpression) write("(");
|
|
|
|
emit(node.expression);
|
|
|
|
if (isArrowExpression) write(")");
|
|
|
|
write(";");
|
2014-08-16 00:49:09 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
|
|
|
function emitIfStatement(node: IfStatement) {
|
2014-08-16 00:24:44 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emitEmbeddedStatement(node.elseStatement);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-08-16 00:24:44 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
|
|
|
function emitDoStatement(node: DoStatement) {
|
|
|
|
write("do");
|
|
|
|
emitEmbeddedStatement(node.statement);
|
|
|
|
if (node.statement.kind === SyntaxKind.Block) {
|
|
|
|
write(" ");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
writeLine();
|
|
|
|
}
|
|
|
|
write("while (");
|
|
|
|
emit(node.expression);
|
|
|
|
write(");");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitWhileStatement(node: WhileStatement) {
|
|
|
|
write("while (");
|
|
|
|
emit(node.expression);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(")");
|
2014-07-17 00:39:14 +02:00
|
|
|
emitEmbeddedStatement(node.statement);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitForStatement(node: ForStatement) {
|
|
|
|
var endPos = emitToken(SyntaxKind.ForKeyword, node.pos);
|
|
|
|
write(" ");
|
|
|
|
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
|
|
|
|
if (node.declarations) {
|
|
|
|
emitToken(SyntaxKind.VarKeyword, endPos);
|
|
|
|
write(" ");
|
|
|
|
emitCommaList(node.declarations);
|
|
|
|
}
|
|
|
|
if (node.initializer) {
|
|
|
|
emit(node.initializer);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
write(";");
|
|
|
|
emitOptional(" ", node.condition);
|
|
|
|
write(";");
|
|
|
|
emitOptional(" ", node.iterator);
|
|
|
|
write(")");
|
|
|
|
emitEmbeddedStatement(node.statement);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitForInStatement(node: ForInStatement) {
|
|
|
|
var endPos = emitToken(SyntaxKind.ForKeyword, node.pos);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(" ");
|
2014-07-17 00:39:14 +02:00
|
|
|
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
|
|
|
|
if (node.declaration) {
|
|
|
|
emitToken(SyntaxKind.VarKeyword, endPos);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(" ");
|
2014-07-17 00:39:14 +02:00
|
|
|
emit(node.declaration);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
else {
|
|
|
|
emit(node.variable);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
write(" in ");
|
|
|
|
emit(node.expression);
|
|
|
|
emitToken(SyntaxKind.CloseParenToken, node.expression.end);
|
|
|
|
emitEmbeddedStatement(node.statement);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitBreakOrContinueStatement(node: BreakOrContinueStatement) {
|
|
|
|
emitToken(node.kind === SyntaxKind.BreakStatement ? SyntaxKind.BreakKeyword : SyntaxKind.ContinueKeyword, node.pos);
|
|
|
|
emitOptional(" ", node.label);
|
|
|
|
write(";");
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitReturnStatement(node: ReturnStatement) {
|
2014-08-16 00:16:17 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitToken(SyntaxKind.ReturnKeyword, node.pos);
|
|
|
|
emitOptional(" ", node.expression);
|
|
|
|
write(";");
|
2014-08-16 00:16:17 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitWithStatement(node: WhileStatement) {
|
|
|
|
write("with (");
|
|
|
|
emit(node.expression);
|
|
|
|
write(")");
|
|
|
|
emitEmbeddedStatement(node.statement);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitSwitchStatement(node: SwitchStatement) {
|
|
|
|
var endPos = emitToken(SyntaxKind.SwitchKeyword, node.pos);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(" ");
|
2014-07-17 00:39:14 +02:00
|
|
|
emitToken(SyntaxKind.OpenParenToken, endPos);
|
|
|
|
emit(node.expression);
|
|
|
|
endPos = emitToken(SyntaxKind.CloseParenToken, node.expression.end);
|
|
|
|
write(" ");
|
|
|
|
emitToken(SyntaxKind.OpenBraceToken, endPos);
|
2014-07-13 01:04:16 +02:00
|
|
|
increaseIndent();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitLines(node.clauses);
|
2014-07-13 01:04:16 +02:00
|
|
|
decreaseIndent();
|
2014-07-17 00:39:14 +02:00
|
|
|
writeLine();
|
|
|
|
emitToken(SyntaxKind.CloseBraceToken, node.clauses.end);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitCaseOrDefaultClause(node: CaseOrDefaultClause) {
|
|
|
|
if (node.kind === SyntaxKind.CaseClause) {
|
|
|
|
write("case ");
|
|
|
|
emit(node.expression);
|
|
|
|
write(":");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
write("default:");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
increaseIndent();
|
|
|
|
emitLines(node.statements);
|
|
|
|
decreaseIndent();
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitThrowStatement(node: ThrowStatement) {
|
|
|
|
write("throw ");
|
|
|
|
emit(node.expression);
|
|
|
|
write(";");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitTryStatement(node: TryStatement) {
|
|
|
|
write("try ");
|
|
|
|
emit(node.tryBlock);
|
|
|
|
emit(node.catchBlock);
|
|
|
|
if (node.finallyBlock) {
|
|
|
|
writeLine();
|
|
|
|
write("finally ");
|
|
|
|
emit(node.finallyBlock);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitCatchBlock(node: CatchBlock) {
|
|
|
|
writeLine();
|
|
|
|
var endPos = emitToken(SyntaxKind.CatchKeyword, node.pos);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(" ");
|
2014-07-17 00:39:14 +02:00
|
|
|
emitToken(SyntaxKind.OpenParenToken, endPos);
|
2014-07-13 01:04:16 +02:00
|
|
|
emit(node.variable);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitToken(SyntaxKind.CloseParenToken, node.variable.end);
|
|
|
|
write(" ");
|
|
|
|
emitBlock(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39: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
|
|
|
function emitLabelledStatement(node: LabelledStatement) {
|
|
|
|
emit(node.label);
|
|
|
|
write(": ");
|
|
|
|
emit(node.statement);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39: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-07-17 00:39:14 +02:00
|
|
|
function emitModuleMemberName(node: Declaration) {
|
|
|
|
emitStart(node.name);
|
|
|
|
if (node.flags & NodeFlags.Export) {
|
|
|
|
var container = getContainingModule(node);
|
2014-07-19 02:04:06 +02:00
|
|
|
write(container ? resolver.getLocalNameOfContainer(container) : "exports");
|
2014-07-17 00:39:14 +02:00
|
|
|
write(".");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
emitNode(node.name);
|
|
|
|
emitEnd(node.name);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitVariableDeclaration(node: VariableDeclaration) {
|
2014-08-12 00:54:12 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitModuleMemberName(node);
|
|
|
|
emitOptional(" = ", node.initializer);
|
2014-08-12 00:54:12 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitVariableStatement(node: VariableStatement) {
|
2014-08-12 00:54:12 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (!(node.flags & NodeFlags.Export)) write("var ");
|
|
|
|
emitCommaList(node.declarations);
|
|
|
|
write(";");
|
2014-08-12 00:54:12 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitParameter(node: ParameterDeclaration) {
|
2014-08-14 14:47:38 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
emit(node.name);
|
2014-08-14 14:47:38 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitDefaultValueAssignments(node: FunctionDeclaration) {
|
|
|
|
forEach(node.parameters, param => {
|
|
|
|
if (param.initializer) {
|
|
|
|
writeLine();
|
|
|
|
emitStart(param);
|
|
|
|
write("if (");
|
|
|
|
emitNode(param.name);
|
|
|
|
write(" === void 0)");
|
|
|
|
emitEnd(param);
|
|
|
|
write(" { ");
|
|
|
|
emitStart(param);
|
|
|
|
emitNode(param.name);
|
|
|
|
write(" = ");
|
|
|
|
emitNode(param.initializer);
|
|
|
|
emitEnd(param);
|
|
|
|
write("; }");
|
|
|
|
}
|
|
|
|
});
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitRestParameter(node: FunctionDeclaration) {
|
|
|
|
if (hasRestParameters(node)) {
|
|
|
|
var restIndex = node.parameters.length - 1;
|
|
|
|
var restParam = node.parameters[restIndex];
|
|
|
|
writeLine();
|
2014-08-14 14:47:38 +02:00
|
|
|
emitLeadingComments(restParam);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitStart(restParam);
|
|
|
|
write("var ");
|
|
|
|
emitNode(restParam.name);
|
|
|
|
write(" = [];");
|
|
|
|
emitEnd(restParam);
|
2014-08-14 14:47:38 +02:00
|
|
|
emitTrailingComments(restParam);
|
2014-07-17 00:39:14 +02:00
|
|
|
writeLine();
|
|
|
|
write("for (");
|
|
|
|
emitStart(restParam);
|
|
|
|
write("var _i = " + restIndex + ";");
|
|
|
|
emitEnd(restParam);
|
|
|
|
write(" ");
|
|
|
|
emitStart(restParam);
|
|
|
|
write("_i < arguments.length;");
|
|
|
|
emitEnd(restParam);
|
|
|
|
write(" ");
|
|
|
|
emitStart(restParam);
|
|
|
|
write("_i++");
|
|
|
|
emitEnd(restParam);
|
|
|
|
write(") {");
|
|
|
|
increaseIndent();
|
|
|
|
writeLine();
|
|
|
|
emitStart(restParam);
|
|
|
|
emitNode(restParam.name);
|
|
|
|
write("[_i - " + restIndex + "] = arguments[_i];");
|
|
|
|
emitEnd(restParam);
|
|
|
|
decreaseIndent();
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
|
|
|
write("}");
|
|
|
|
}
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
|
|
|
function emitAccessor(node: AccessorDeclaration) {
|
2014-08-14 15:12:14 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(node.kind === SyntaxKind.GetAccessor ? "get " : "set ");
|
2014-07-13 01:04:16 +02:00
|
|
|
emit(node.name);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitSignatureAndBody(node);
|
2014-08-14 15:12:14 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitFunctionDeclaration(node: FunctionDeclaration) {
|
2014-08-22 23:40:47 +02:00
|
|
|
if (!node.body) {
|
|
|
|
return emitPinnedOrTripleSlashComments(node);
|
|
|
|
}
|
|
|
|
|
2014-08-14 15:21:30 +02:00
|
|
|
if (node.kind !== SyntaxKind.Method) {
|
|
|
|
// Methods will emit the comments as part of emitting method declaration
|
|
|
|
emitLeadingComments(node);
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
write("function ");
|
|
|
|
if (node.kind === SyntaxKind.FunctionDeclaration || (node.kind === SyntaxKind.FunctionExpression && node.name)) {
|
|
|
|
emit(node.name);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
emitSignatureAndBody(node);
|
2014-08-14 15:21:30 +02:00
|
|
|
if (node.kind !== SyntaxKind.Method) {
|
|
|
|
emitTrailingComments(node);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitCaptureThisForNodeIfNecessary(node: Node): void {
|
|
|
|
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.CaptureThis) {
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitStart(node);
|
|
|
|
write("var _this = this;");
|
|
|
|
emitEnd(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-18 18:56:10 +02:00
|
|
|
function emitSignatureParameters(node: FunctionDeclaration) {
|
2014-08-15 22:18:54 +02:00
|
|
|
increaseIndent();
|
2014-07-17 00:39:14 +02:00
|
|
|
write("(");
|
2014-07-18 04:54:21 +02:00
|
|
|
if (node) {
|
|
|
|
emitCommaList(node.parameters, node.parameters.length - (hasRestParameters(node) ? 1 : 0));
|
|
|
|
}
|
|
|
|
write(")");
|
2014-08-15 22:18:54 +02:00
|
|
|
decreaseIndent();
|
2014-07-18 04:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function emitSignatureAndBody(node: FunctionDeclaration) {
|
2014-07-18 18:56:10 +02:00
|
|
|
emitSignatureParameters(node);
|
2014-07-18 04:54:21 +02:00
|
|
|
write(" {");
|
2014-07-17 00:39:14 +02:00
|
|
|
scopeEmitStart(node);
|
|
|
|
increaseIndent();
|
2014-07-19 01:59:52 +02:00
|
|
|
|
2014-08-19 21:06:52 +02:00
|
|
|
emitDetachedComments(node.body.kind === SyntaxKind.FunctionBlock ? (<Block>node.body).statements : node.body);
|
|
|
|
|
2014-07-19 01:59:52 +02:00
|
|
|
var startIndex = 0;
|
|
|
|
if (node.body.kind === SyntaxKind.FunctionBlock) {
|
|
|
|
startIndex = emitDirectivePrologues((<Block>node.body).statements, /*startWithNewLine*/ true);
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
var outPos = writer.getTextPos();
|
|
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
|
|
emitDefaultValueAssignments(node);
|
|
|
|
emitRestParameter(node);
|
|
|
|
if (node.body.kind !== SyntaxKind.FunctionBlock && outPos === writer.getTextPos()) {
|
|
|
|
decreaseIndent();
|
|
|
|
write(" ");
|
|
|
|
emitStart(node.body);
|
|
|
|
write("return ");
|
|
|
|
emitNode(node.body);
|
|
|
|
emitEnd(node.body);
|
|
|
|
write("; ");
|
|
|
|
emitStart(node.body);
|
|
|
|
write("}");
|
|
|
|
emitEnd(node.body);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (node.body.kind === SyntaxKind.FunctionBlock) {
|
2014-07-19 01:59:52 +02:00
|
|
|
emitLinesStartingAt((<Block>node.body).statements, startIndex);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
writeLine();
|
2014-08-19 21:06:52 +02:00
|
|
|
emitLeadingComments(node.body);
|
2014-07-17 00:39:14 +02:00
|
|
|
write("return ");
|
|
|
|
emit(node.body);
|
|
|
|
write(";");
|
2014-08-19 21:06:52 +02:00
|
|
|
emitTrailingComments(node.body);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
if (node.body.kind === SyntaxKind.FunctionBlock) {
|
2014-08-22 02:17:02 +02:00
|
|
|
emitLeadingCommentsOfPosition((<Block>node.body).statements.end);
|
|
|
|
decreaseIndent();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitToken(SyntaxKind.CloseBraceToken, (<Block>node.body).statements.end);
|
|
|
|
}
|
|
|
|
else {
|
2014-08-22 02:17:02 +02:00
|
|
|
decreaseIndent();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitStart(node.body);
|
|
|
|
write("}");
|
|
|
|
emitEnd(node.body);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
scopeEmitEnd();
|
|
|
|
if (node.flags & NodeFlags.Export) {
|
|
|
|
writeLine();
|
|
|
|
emitStart(node);
|
|
|
|
emitModuleMemberName(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(" = ");
|
2014-07-17 00:39:14 +02:00
|
|
|
emit(node.name);
|
|
|
|
emitEnd(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(";");
|
|
|
|
}
|
2014-07-17 00:39: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) {
|
|
|
|
var func = (<CallExpression>expr).func;
|
|
|
|
if (func && func.kind === SyntaxKind.SuperKeyword) {
|
|
|
|
return <ExpressionStatement>statement;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function emitParameterPropertyAssignments(node: ConstructorDeclaration) {
|
|
|
|
forEach(node.parameters, param => {
|
|
|
|
if (param.flags & (NodeFlags.Public | NodeFlags.Private)) {
|
|
|
|
writeLine();
|
|
|
|
emitStart(param);
|
|
|
|
emitStart(param.name);
|
|
|
|
write("this.");
|
|
|
|
emitNode(param.name);
|
|
|
|
emitEnd(param.name);
|
|
|
|
write(" = ");
|
|
|
|
emit(param.name);
|
|
|
|
write(";");
|
|
|
|
emitEnd(param);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function emitMemberAccess(memberName: Identifier) {
|
|
|
|
if (memberName.kind === SyntaxKind.StringLiteral || memberName.kind === SyntaxKind.NumericLiteral) {
|
|
|
|
write("[");
|
|
|
|
emitNode(memberName);
|
|
|
|
write("]");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write(".");
|
|
|
|
emitNode(memberName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function emitMemberAssignments(node: ClassDeclaration, staticFlag: NodeFlags) {
|
|
|
|
forEach(node.members, member => {
|
|
|
|
if (member.kind === SyntaxKind.Property && (member.flags & NodeFlags.Static) === staticFlag && (<PropertyDeclaration>member).initializer) {
|
|
|
|
writeLine();
|
2014-08-14 15:31:00 +02:00
|
|
|
emitLeadingComments(member);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitStart(member);
|
|
|
|
emitStart((<PropertyDeclaration>member).name);
|
|
|
|
if (staticFlag) {
|
|
|
|
emitNode(node.name);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("this");
|
|
|
|
}
|
|
|
|
emitMemberAccess((<PropertyDeclaration>member).name);
|
|
|
|
emitEnd((<PropertyDeclaration>member).name);
|
|
|
|
write(" = ");
|
|
|
|
emit((<PropertyDeclaration>member).initializer);
|
|
|
|
write(";");
|
|
|
|
emitEnd(member);
|
2014-08-14 15:31:00 +02:00
|
|
|
emitTrailingComments(member);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function emitMemberFunctions(node: ClassDeclaration) {
|
|
|
|
forEach(node.members, member => {
|
|
|
|
if (member.kind === SyntaxKind.Method) {
|
2014-08-22 23:40:47 +02:00
|
|
|
if (!(<MethodDeclaration>member).body) {
|
|
|
|
return emitPinnedOrTripleSlashComments(member);
|
|
|
|
}
|
|
|
|
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
2014-08-14 15:21:30 +02:00
|
|
|
emitLeadingComments(member);
|
2014-07-13 01:04:16 +02:00
|
|
|
emitStart(member);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitStart((<MethodDeclaration>member).name);
|
2014-07-13 01:04:16 +02:00
|
|
|
emitNode(node.name);
|
|
|
|
if (!(member.flags & NodeFlags.Static)) {
|
|
|
|
write(".prototype");
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
emitMemberAccess((<MethodDeclaration>member).name);
|
|
|
|
emitEnd((<MethodDeclaration>member).name);
|
|
|
|
write(" = ");
|
|
|
|
emitStart(member);
|
|
|
|
emitFunctionDeclaration(<MethodDeclaration>member);
|
|
|
|
emitEnd(member);
|
|
|
|
emitEnd(member);
|
|
|
|
write(";");
|
2014-08-14 15:21:30 +02:00
|
|
|
emitTrailingComments(member);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
else if (member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor) {
|
|
|
|
var accessors = getAllAccessorDeclarations(node, <AccessorDeclaration>member);
|
|
|
|
if (member === accessors.firstAccessor) {
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitStart(member);
|
|
|
|
write("Object.defineProperty(");
|
|
|
|
emitStart((<AccessorDeclaration>member).name);
|
|
|
|
emitNode(node.name);
|
|
|
|
if (!(member.flags & NodeFlags.Static)) {
|
|
|
|
write(".prototype");
|
|
|
|
}
|
|
|
|
write(", ");
|
|
|
|
emitQuotedIdentifier((<AccessorDeclaration>member).name);
|
|
|
|
emitEnd((<AccessorDeclaration>member).name);
|
|
|
|
write(", {");
|
|
|
|
increaseIndent();
|
|
|
|
if (accessors.getAccessor) {
|
|
|
|
writeLine();
|
2014-08-14 15:12:14 +02:00
|
|
|
emitLeadingComments(accessors.getAccessor);
|
2014-07-17 00:39:14 +02:00
|
|
|
write("get: ");
|
|
|
|
emitStart(accessors.getAccessor);
|
|
|
|
write("function ");
|
|
|
|
emitSignatureAndBody(accessors.getAccessor);
|
|
|
|
emitEnd(accessors.getAccessor);
|
2014-08-14 15:12:14 +02:00
|
|
|
emitTrailingComments(accessors.getAccessor);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(",");
|
|
|
|
}
|
|
|
|
if (accessors.setAccessor) {
|
|
|
|
writeLine();
|
2014-08-14 15:12:14 +02:00
|
|
|
emitLeadingComments(accessors.setAccessor);
|
2014-07-17 00:39:14 +02:00
|
|
|
write("set: ");
|
|
|
|
emitStart(accessors.setAccessor);
|
|
|
|
write("function ");
|
|
|
|
emitSignatureAndBody(accessors.setAccessor);
|
|
|
|
emitEnd(accessors.setAccessor);
|
2014-08-14 15:12:14 +02:00
|
|
|
emitTrailingComments(accessors.setAccessor);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(",");
|
|
|
|
}
|
|
|
|
writeLine();
|
|
|
|
write("enumerable: true,");
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
write("configurable: true");
|
|
|
|
decreaseIndent();
|
|
|
|
writeLine();
|
|
|
|
write("});");
|
|
|
|
emitEnd(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-07-17 00:39:14 +02:00
|
|
|
function emitClassDeclaration(node: ClassDeclaration) {
|
2014-08-14 15:42:18 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
write("var ");
|
2014-07-13 01:04:16 +02:00
|
|
|
emit(node.name);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(" = (function (");
|
2014-08-14 15:42:18 +02:00
|
|
|
if (node.baseType) {
|
|
|
|
write("_super");
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
write(") {");
|
|
|
|
increaseIndent();
|
|
|
|
scopeEmitStart(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
if (node.baseType) {
|
|
|
|
writeLine();
|
|
|
|
emitStart(node.baseType);
|
2014-07-17 00:39:14 +02:00
|
|
|
write("__extends(");
|
|
|
|
emit(node.name);
|
|
|
|
write(", _super);");
|
2014-07-13 01:04:16 +02:00
|
|
|
emitEnd(node.baseType);
|
|
|
|
}
|
|
|
|
writeLine();
|
2014-08-15 00:41:57 +02:00
|
|
|
emitConstructorOfClass();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitMemberFunctions(node);
|
|
|
|
emitMemberAssignments(node, NodeFlags.Static);
|
|
|
|
writeLine();
|
|
|
|
function emitClassReturnStatement() {
|
|
|
|
write("return ");
|
|
|
|
emitNode(node.name);
|
|
|
|
}
|
|
|
|
emitToken(SyntaxKind.CloseBraceToken, node.members.end, emitClassReturnStatement);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(";");
|
2014-07-17 00:39:14 +02:00
|
|
|
decreaseIndent();
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitToken(SyntaxKind.CloseBraceToken, node.members.end);
|
|
|
|
scopeEmitEnd();
|
2014-07-13 01:04:16 +02:00
|
|
|
emitStart(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(")(");
|
|
|
|
if (node.baseType) {
|
|
|
|
emit(node.baseType.typeName);
|
|
|
|
}
|
|
|
|
write(");");
|
2014-07-13 01:04:16 +02:00
|
|
|
emitEnd(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (node.flags & NodeFlags.Export) {
|
|
|
|
writeLine();
|
|
|
|
emitStart(node);
|
|
|
|
emitModuleMemberName(node);
|
|
|
|
write(" = ");
|
|
|
|
emit(node.name);
|
|
|
|
emitEnd(node);
|
|
|
|
write(";");
|
|
|
|
}
|
2014-08-14 15:42:18 +02:00
|
|
|
emitTrailingComments(node);
|
2014-08-15 00:41:57 +02:00
|
|
|
|
|
|
|
function emitConstructorOfClass() {
|
2014-08-22 23:40:47 +02:00
|
|
|
// Emit the constructor overload pinned comments
|
|
|
|
forEach(node.members, member => {
|
|
|
|
if (member.kind === SyntaxKind.Constructor && !(<ConstructorDeclaration>member).body) {
|
|
|
|
emitPinnedOrTripleSlashComments(member);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2014-08-15 00:41:57 +02:00
|
|
|
var ctor = getFirstConstructorWithBody(node);
|
|
|
|
if (ctor) {
|
|
|
|
emitLeadingComments(ctor);
|
|
|
|
}
|
|
|
|
emitStart(<Node>ctor || node);
|
|
|
|
write("function ");
|
|
|
|
emit(node.name);
|
|
|
|
emitSignatureParameters(ctor);
|
|
|
|
write(" {");
|
|
|
|
scopeEmitStart(node, "constructor");
|
|
|
|
increaseIndent();
|
2014-08-19 21:38:56 +02:00
|
|
|
if (ctor) {
|
|
|
|
emitDetachedComments((<Block>ctor.body).statements);
|
|
|
|
}
|
2014-08-15 00:41:57 +02:00
|
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
|
|
if (ctor) {
|
|
|
|
emitDefaultValueAssignments(ctor);
|
|
|
|
emitRestParameter(ctor);
|
|
|
|
if (node.baseType) {
|
|
|
|
var superCall = findInitialSuperCall(ctor);
|
|
|
|
if (superCall) {
|
|
|
|
writeLine();
|
|
|
|
emit(superCall);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
emitParameterPropertyAssignments(ctor);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (node.baseType) {
|
|
|
|
writeLine();
|
|
|
|
emitStart(node.baseType);
|
|
|
|
write("_super.apply(this, arguments);");
|
|
|
|
emitEnd(node.baseType);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
emitMemberAssignments(node, /*nonstatic*/0);
|
|
|
|
if (ctor) {
|
|
|
|
var statements: Node[] = (<Block>ctor.body).statements;
|
|
|
|
if (superCall) statements = statements.slice(1);
|
|
|
|
emitLines(statements);
|
|
|
|
}
|
|
|
|
writeLine();
|
2014-08-22 02:17:32 +02:00
|
|
|
if (ctor) {
|
|
|
|
emitLeadingCommentsOfPosition((<Block>ctor.body).statements.end);
|
|
|
|
}
|
|
|
|
decreaseIndent();
|
2014-08-15 00:41:57 +02:00
|
|
|
emitToken(SyntaxKind.CloseBraceToken, ctor ? (<Block>ctor.body).statements.end : node.members.end);
|
|
|
|
scopeEmitEnd();
|
|
|
|
emitEnd(<Node>ctor || node);
|
|
|
|
if (ctor) {
|
|
|
|
emitTrailingComments(ctor);
|
|
|
|
}
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-08-22 23:17:52 +02:00
|
|
|
function emitInterfaceDeclaration(node: InterfaceDeclaration) {
|
|
|
|
emitPinnedOrTripleSlashComments(node);
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitEnumDeclaration(node: EnumDeclaration) {
|
2014-08-14 15:48:40 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (!(node.flags & NodeFlags.Export)) {
|
|
|
|
emitStart(node);
|
|
|
|
write("var ");
|
|
|
|
emit(node.name);
|
|
|
|
emitEnd(node);
|
|
|
|
write(";");
|
|
|
|
}
|
|
|
|
writeLine();
|
2014-07-13 01:04:16 +02:00
|
|
|
emitStart(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
write("(function (");
|
2014-07-19 02:04:06 +02:00
|
|
|
emitStart(node.name);
|
|
|
|
write(resolver.getLocalNameOfContainer(node));
|
|
|
|
emitEnd(node.name);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(") {");
|
2014-07-13 01:04:16 +02:00
|
|
|
increaseIndent();
|
|
|
|
scopeEmitStart(node);
|
2014-08-15 00:41:57 +02:00
|
|
|
emitEnumMemberDeclarations();
|
2014-07-13 01:04:16 +02:00
|
|
|
decreaseIndent();
|
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitToken(SyntaxKind.CloseBraceToken, node.members.end);
|
2014-07-13 01:04:16 +02:00
|
|
|
scopeEmitEnd();
|
2014-07-17 00:39:14 +02:00
|
|
|
write(")(");
|
|
|
|
emitModuleMemberName(node);
|
|
|
|
write(" || (");
|
2014-07-13 01:04:16 +02:00
|
|
|
emitModuleMemberName(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(" = {}));");
|
2014-07-13 01:04:16 +02:00
|
|
|
emitEnd(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (node.flags & NodeFlags.Export) {
|
|
|
|
writeLine();
|
|
|
|
emitStart(node);
|
|
|
|
write("var ");
|
|
|
|
emit(node.name);
|
|
|
|
write(" = ");
|
|
|
|
emitModuleMemberName(node);
|
|
|
|
emitEnd(node);
|
|
|
|
write(";");
|
|
|
|
}
|
2014-08-14 15:48:40 +02:00
|
|
|
emitTrailingComments(node);
|
2014-08-15 00:41:57 +02:00
|
|
|
|
|
|
|
function emitEnumMemberDeclarations() {
|
|
|
|
forEach(node.members, member => {
|
|
|
|
writeLine();
|
|
|
|
emitLeadingComments(member);
|
|
|
|
emitStart(member);
|
|
|
|
write(resolver.getLocalNameOfContainer(node));
|
|
|
|
write("[");
|
|
|
|
write(resolver.getLocalNameOfContainer(node));
|
|
|
|
write("[");
|
|
|
|
emitQuotedIdentifier(member.name);
|
|
|
|
write("] = ");
|
|
|
|
if (member.initializer) {
|
|
|
|
emit(member.initializer);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write(resolver.getEnumMemberValue(member).toString());
|
|
|
|
}
|
|
|
|
write("] = ");
|
|
|
|
emitQuotedIdentifier(member.name);
|
|
|
|
emitEnd(member);
|
|
|
|
write(";");
|
|
|
|
emitTrailingComments(member);
|
|
|
|
});
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration {
|
|
|
|
if (moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) {
|
|
|
|
var recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(<ModuleDeclaration>moduleDeclaration.body);
|
|
|
|
return recursiveInnerModule || <ModuleDeclaration>moduleDeclaration.body;
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitModuleDeclaration(node: ModuleDeclaration) {
|
2014-08-22 23:50:56 +02:00
|
|
|
if (!isInstantiated(node)) {
|
|
|
|
return emitPinnedOrTripleSlashComments(node);
|
|
|
|
}
|
|
|
|
|
2014-08-14 15:53:37 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (!(node.flags & NodeFlags.Export)) {
|
|
|
|
emitStart(node);
|
|
|
|
write("var ");
|
|
|
|
emit(node.name);
|
|
|
|
write(";");
|
|
|
|
emitEnd(node);
|
|
|
|
writeLine();
|
|
|
|
}
|
|
|
|
emitStart(node);
|
|
|
|
write("(function (");
|
2014-07-19 02:04:06 +02:00
|
|
|
emitStart(node.name);
|
|
|
|
write(resolver.getLocalNameOfContainer(node));
|
|
|
|
emitEnd(node.name);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(") ");
|
|
|
|
if (node.body.kind === SyntaxKind.ModuleBlock) {
|
|
|
|
emit(node.body);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
write("{");
|
|
|
|
increaseIndent();
|
|
|
|
scopeEmitStart(node);
|
|
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
|
|
writeLine();
|
|
|
|
emit(node.body);
|
|
|
|
decreaseIndent();
|
|
|
|
writeLine();
|
|
|
|
var moduleBlock = <Block>getInnerMostModuleDeclarationFromDottedModule(node).body;
|
|
|
|
emitToken(SyntaxKind.CloseBraceToken, moduleBlock.statements.end);
|
|
|
|
scopeEmitEnd();
|
|
|
|
}
|
|
|
|
write(")(");
|
|
|
|
emitModuleMemberName(node);
|
|
|
|
write(" || (");
|
|
|
|
emitModuleMemberName(node);
|
|
|
|
write(" = {}));");
|
|
|
|
emitEnd(node);
|
|
|
|
if (node.flags & NodeFlags.Export) {
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
|
|
|
emitStart(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
write("var ");
|
|
|
|
emit(node.name);
|
2014-07-13 01:04:16 +02:00
|
|
|
write(" = ");
|
2014-07-17 00:39:14 +02:00
|
|
|
emitModuleMemberName(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
emitEnd(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(";");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-08-14 15:53:37 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitImportDeclaration(node: ImportDeclaration) {
|
|
|
|
var emitImportDeclaration = resolver.isReferencedImportDeclaration(node);
|
|
|
|
|
|
|
|
if (!emitImportDeclaration) {
|
|
|
|
// 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
|
2014-07-18 04:11:01 +02:00
|
|
|
emitImportDeclaration = !isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportedViaEntityName(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (emitImportDeclaration) {
|
|
|
|
if (node.externalModuleName && node.parent.kind === SyntaxKind.SourceFile && compilerOptions.module === ModuleKind.AMD) {
|
|
|
|
if (node.flags & NodeFlags.Export) {
|
|
|
|
writeLine();
|
2014-08-14 15:57:59 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitStart(node);
|
|
|
|
emitModuleMemberName(node);
|
|
|
|
write(" = ");
|
|
|
|
emit(node.name);
|
|
|
|
write(";");
|
|
|
|
emitEnd(node);
|
2014-08-14 15:57:59 +02:00
|
|
|
emitTrailingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
writeLine();
|
2014-08-14 15:57:59 +02:00
|
|
|
emitLeadingComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitStart(node);
|
|
|
|
if (!(node.flags & NodeFlags.Export)) write("var ");
|
|
|
|
emitModuleMemberName(node);
|
|
|
|
write(" = ");
|
|
|
|
if (node.entityName) {
|
|
|
|
emit(node.entityName);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("require(");
|
|
|
|
emitStart(node.externalModuleName);
|
|
|
|
emitLiteral(node.externalModuleName);
|
|
|
|
emitEnd(node.externalModuleName);
|
|
|
|
emitToken(SyntaxKind.CloseParenToken, node.externalModuleName.end);
|
|
|
|
}
|
|
|
|
write(";");
|
|
|
|
emitEnd(node);
|
2014-08-14 15:57:59 +02:00
|
|
|
emitTrailingComments(node);
|
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-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function getExternalImportDeclarations(node: SourceFile): ImportDeclaration[] {
|
|
|
|
var result: ImportDeclaration[] = [];
|
|
|
|
forEach(node.statements, stat => {
|
|
|
|
if (stat.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>stat).externalModuleName && resolver.isReferencedImportDeclaration(stat)) {
|
|
|
|
result.push(<ImportDeclaration>stat);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return result;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function getFirstExportAssignment(sourceFile: SourceFile) {
|
|
|
|
return forEach(sourceFile.statements, node => {
|
|
|
|
if (node.kind === SyntaxKind.ExportAssignment) {
|
|
|
|
return <ExportAssignment>node;
|
|
|
|
}
|
|
|
|
});
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-18 02:43:48 +02:00
|
|
|
function emitAMDModule(node: SourceFile, startIndex: number) {
|
2014-07-17 00:39:14 +02:00
|
|
|
var imports = getExternalImportDeclarations(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
write("define([\"require\", \"exports\"");
|
|
|
|
forEach(imports, imp => {
|
|
|
|
write(", ");
|
|
|
|
emitLiteral(imp.externalModuleName);
|
|
|
|
});
|
|
|
|
forEach(node.amdDependencies, amdDependency => {
|
|
|
|
var text = "\"" + amdDependency + "\"";
|
|
|
|
write(", ");
|
|
|
|
write(text);
|
|
|
|
});
|
|
|
|
write("], function (require, exports");
|
|
|
|
forEach(imports, imp => {
|
|
|
|
write(", ");
|
|
|
|
emit(imp.name);
|
|
|
|
});
|
|
|
|
write(") {");
|
2014-07-13 01:04:16 +02:00
|
|
|
increaseIndent();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitCaptureThisForNodeIfNecessary(node);
|
2014-07-18 02:43:48 +02:00
|
|
|
emitLinesStartingAt(node.statements, startIndex);
|
2014-07-17 00:39:14 +02:00
|
|
|
var exportName = resolver.getExportAssignmentName(node);
|
|
|
|
if (exportName) {
|
|
|
|
writeLine();
|
|
|
|
var exportAssignement = getFirstExportAssignment(node);
|
|
|
|
emitStart(exportAssignement);
|
|
|
|
write("return ");
|
|
|
|
emitStart(exportAssignement.exportName);
|
|
|
|
write(exportName);
|
|
|
|
emitEnd(exportAssignement.exportName);
|
|
|
|
write(";");
|
|
|
|
emitEnd(exportAssignement);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
decreaseIndent();
|
|
|
|
writeLine();
|
2014-07-17 00:39:14 +02:00
|
|
|
write("});");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
2014-07-18 02:43:48 +02:00
|
|
|
function emitCommonJSModule(node: SourceFile, startIndex: number) {
|
2014-07-17 00:39:14 +02:00
|
|
|
emitCaptureThisForNodeIfNecessary(node);
|
2014-07-18 02:43:48 +02:00
|
|
|
emitLinesStartingAt(node.statements, startIndex);
|
2014-07-17 00:39:14 +02:00
|
|
|
var exportName = resolver.getExportAssignmentName(node);
|
|
|
|
if (exportName) {
|
|
|
|
writeLine();
|
|
|
|
var exportAssignement = getFirstExportAssignment(node);
|
|
|
|
emitStart(exportAssignement);
|
|
|
|
write("module.exports = ");
|
|
|
|
emitStart(exportAssignement.exportName);
|
|
|
|
write(exportName);
|
|
|
|
emitEnd(exportAssignement.exportName);
|
|
|
|
write(";");
|
|
|
|
emitEnd(exportAssignement);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-19 01:59:52 +02:00
|
|
|
function emitDirectivePrologues(statements: Statement[], startWithNewLine: boolean): number {
|
|
|
|
for (var i = 0; i < statements.length; ++i) {
|
2014-07-23 19:40:39 +02:00
|
|
|
if (isPrologueDirective(statements[i])) {
|
2014-07-19 01:59:52 +02:00
|
|
|
if (startWithNewLine || i > 0) {
|
2014-07-18 02:43:48 +02:00
|
|
|
writeLine();
|
|
|
|
}
|
2014-07-19 01:59:52 +02:00
|
|
|
emit(statements[i]);
|
2014-07-18 02:43:48 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-19 01:59:52 +02:00
|
|
|
// return index of the first non prologue directive
|
|
|
|
return i;
|
2014-07-18 02:43:48 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-19 01:59:52 +02:00
|
|
|
return statements.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
function emitSourceFile(node: SourceFile) {
|
|
|
|
currentSourceFile = node;
|
2014-08-21 22:44:26 +02:00
|
|
|
// Start new file on new line
|
|
|
|
writeLine();
|
2014-08-19 19:43:13 +02:00
|
|
|
emitDetachedComments(node);
|
2014-07-19 01:59:52 +02:00
|
|
|
// emit prologue directives prior to __extends
|
|
|
|
var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (!extendsEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitExtends) {
|
|
|
|
writeLine();
|
|
|
|
write("var __extends = this.__extends || function (d, b) {");
|
|
|
|
increaseIndent();
|
|
|
|
writeLine();
|
|
|
|
write("for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];");
|
|
|
|
writeLine();
|
|
|
|
write("function __() { this.constructor = d; }");
|
|
|
|
writeLine();
|
|
|
|
write("__.prototype = b.prototype;");
|
|
|
|
writeLine();
|
|
|
|
write("d.prototype = new __();");
|
|
|
|
decreaseIndent();
|
|
|
|
writeLine();
|
|
|
|
write("};");
|
|
|
|
extendsEmitted = true;
|
|
|
|
}
|
2014-07-18 04:11:01 +02:00
|
|
|
if (isExternalModule(node)) {
|
2014-07-17 00:39:14 +02:00
|
|
|
if (compilerOptions.module === ModuleKind.AMD) {
|
2014-07-18 02:43:48 +02:00
|
|
|
emitAMDModule(node, startIndex);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-18 02:43:48 +02:00
|
|
|
emitCommonJSModule(node, startIndex);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
emitCaptureThisForNodeIfNecessary(node);
|
2014-07-18 02:43:48 +02:00
|
|
|
emitLinesStartingAt(node.statements, startIndex);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function emitNode(node: Node) {
|
2014-08-22 23:35:07 +02:00
|
|
|
if (!node) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node.flags & NodeFlags.Ambient) {
|
|
|
|
return emitPinnedOrTripleSlashComments(node);
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
switch (node.kind) {
|
|
|
|
case SyntaxKind.Identifier:
|
|
|
|
return emitIdentifier(<Identifier>node);
|
|
|
|
case SyntaxKind.Parameter:
|
|
|
|
return emitParameter(<ParameterDeclaration>node);
|
|
|
|
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:
|
|
|
|
return emitLiteral(<LiteralExpression>node);
|
|
|
|
case SyntaxKind.QualifiedName:
|
|
|
|
return emitPropertyAccess(<QualifiedName>node);
|
|
|
|
case SyntaxKind.ArrayLiteral:
|
|
|
|
return emitArrayLiteral(<ArrayLiteral>node);
|
|
|
|
case SyntaxKind.ObjectLiteral:
|
|
|
|
return emitObjectLiteral(<ObjectLiteral>node);
|
|
|
|
case SyntaxKind.PropertyAssignment:
|
|
|
|
return emitPropertyAssignment(<PropertyDeclaration>node);
|
|
|
|
case SyntaxKind.PropertyAccess:
|
|
|
|
return emitPropertyAccess(<PropertyAccess>node);
|
|
|
|
case SyntaxKind.IndexedAccess:
|
|
|
|
return emitIndexedAccess(<IndexedAccess>node);
|
|
|
|
case SyntaxKind.CallExpression:
|
|
|
|
return emitCallExpression(<CallExpression>node);
|
|
|
|
case SyntaxKind.NewExpression:
|
|
|
|
return emitNewExpression(<NewExpression>node);
|
|
|
|
case SyntaxKind.TypeAssertion:
|
|
|
|
return emit((<TypeAssertion>node).operand);
|
|
|
|
case SyntaxKind.ParenExpression:
|
|
|
|
return emitParenExpression(<ParenExpression>node);
|
|
|
|
case SyntaxKind.FunctionDeclaration:
|
|
|
|
case SyntaxKind.FunctionExpression:
|
|
|
|
case SyntaxKind.ArrowFunction:
|
|
|
|
return emitFunctionDeclaration(<FunctionDeclaration>node);
|
|
|
|
case SyntaxKind.PrefixOperator:
|
|
|
|
case SyntaxKind.PostfixOperator:
|
|
|
|
return emitUnaryExpression(<UnaryExpression>node);
|
|
|
|
case SyntaxKind.BinaryExpression:
|
|
|
|
return emitBinaryExpression(<BinaryExpression>node);
|
|
|
|
case SyntaxKind.ConditionalExpression:
|
|
|
|
return emitConditionalExpression(<ConditionalExpression>node);
|
|
|
|
case SyntaxKind.OmittedExpression:
|
|
|
|
return;
|
|
|
|
case SyntaxKind.Block:
|
|
|
|
case SyntaxKind.TryBlock:
|
|
|
|
case SyntaxKind.FinallyBlock:
|
|
|
|
case SyntaxKind.FunctionBlock:
|
|
|
|
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.LabelledStatement:
|
|
|
|
return emitLabelledStatement(<LabelledStatement>node);
|
|
|
|
case SyntaxKind.ThrowStatement:
|
|
|
|
return emitThrowStatement(<ThrowStatement>node);
|
|
|
|
case SyntaxKind.TryStatement:
|
|
|
|
return emitTryStatement(<TryStatement>node);
|
|
|
|
case SyntaxKind.CatchBlock:
|
|
|
|
return emitCatchBlock(<CatchBlock>node);
|
|
|
|
case SyntaxKind.DebuggerStatement:
|
|
|
|
return emitDebuggerStatement(node);
|
|
|
|
case SyntaxKind.VariableDeclaration:
|
|
|
|
return emitVariableDeclaration(<VariableDeclaration>node);
|
|
|
|
case SyntaxKind.ClassDeclaration:
|
|
|
|
return emitClassDeclaration(<ClassDeclaration>node);
|
2014-08-22 23:17:52 +02:00
|
|
|
case SyntaxKind.InterfaceDeclaration:
|
|
|
|
return emitInterfaceDeclaration(<InterfaceDeclaration>node);
|
2014-07-17 00:39:14 +02:00
|
|
|
case SyntaxKind.EnumDeclaration:
|
|
|
|
return emitEnumDeclaration(<EnumDeclaration>node);
|
|
|
|
case SyntaxKind.ModuleDeclaration:
|
|
|
|
return emitModuleDeclaration(<ModuleDeclaration>node);
|
|
|
|
case SyntaxKind.ImportDeclaration:
|
|
|
|
return emitImportDeclaration(<ImportDeclaration>node);
|
|
|
|
case SyntaxKind.SourceFile:
|
|
|
|
return emitSourceFile(<SourceFile>node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-22 02:17:02 +02:00
|
|
|
function hasDetachedComments(pos: number) {
|
|
|
|
return detachedCommentsInfo !== undefined && detachedCommentsInfo[detachedCommentsInfo.length - 1].nodePos === pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getLeadingCommentsWithoutDetachedComments() {
|
|
|
|
// get the leading comments from detachedPos
|
|
|
|
var leadingComments = getLeadingComments(currentSourceFile.text, detachedCommentsInfo[detachedCommentsInfo.length - 1].detachedCommentEndPos);
|
|
|
|
if (detachedCommentsInfo.length - 1) {
|
|
|
|
detachedCommentsInfo.pop();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
detachedCommentsInfo = undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
return leadingComments;
|
|
|
|
}
|
|
|
|
|
2014-08-22 23:40:47 +02:00
|
|
|
function getLeadingCommentsToEmit(node: Node) {
|
2014-08-16 00:52:30 +02:00
|
|
|
// Emit the leading comments only if the parent's pos doesnt match because parent should take care of emitting these comments
|
|
|
|
if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) {
|
2014-08-19 19:43:13 +02:00
|
|
|
var leadingComments: Comment[];
|
2014-08-22 02:17:02 +02:00
|
|
|
if (hasDetachedComments(node.pos)) {
|
|
|
|
// get comments without detached comments
|
|
|
|
leadingComments = getLeadingCommentsWithoutDetachedComments();
|
2014-08-19 19:43:13 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-08-22 02:17:02 +02:00
|
|
|
// get the leading comments from the node
|
|
|
|
leadingComments = getLeadingCommentsOfNode(node, currentSourceFile);
|
2014-08-19 19:43:13 +02:00
|
|
|
}
|
2014-08-22 23:40:47 +02:00
|
|
|
return leadingComments;
|
2014-08-16 00:52:30 +02:00
|
|
|
}
|
2014-08-12 00:54:12 +02:00
|
|
|
}
|
|
|
|
|
2014-08-22 23:40:47 +02:00
|
|
|
function emitLeadingDeclarationComments(node: Node) {
|
|
|
|
var leadingComments = getLeadingCommentsToEmit(node);
|
|
|
|
emitNewLineBeforeLeadingComments(node, leadingComments, writer);
|
|
|
|
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
|
|
|
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
|
|
|
|
}
|
|
|
|
|
2014-08-16 00:16:17 +02:00
|
|
|
function emitTrailingDeclarationComments(node: Node) {
|
2014-08-16 00:52:30 +02:00
|
|
|
// Emit the trailing comments only if the parent's end doesnt match
|
2014-08-15 01:32:21 +02:00
|
|
|
if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) {
|
|
|
|
var trailingComments = getTrailingComments(currentSourceFile.text, node.end);
|
2014-08-15 23:32:08 +02:00
|
|
|
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
|
|
|
|
emitComments(trailingComments, /*trailingSeparator*/ false, writer, writeComment);
|
2014-08-15 01:32:21 +02:00
|
|
|
}
|
2014-08-12 00:54:12 +02:00
|
|
|
}
|
|
|
|
|
2014-08-22 02:17:02 +02:00
|
|
|
function emitLeadingCommentsOfLocalPosition(pos: number) {
|
|
|
|
var leadingComments: Comment[];
|
|
|
|
if (hasDetachedComments(pos)) {
|
|
|
|
// get comments without detached comments
|
|
|
|
leadingComments = getLeadingCommentsWithoutDetachedComments();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// get the leading comments from the node
|
|
|
|
leadingComments = getLeadingComments(currentSourceFile.text, pos);
|
|
|
|
}
|
|
|
|
emitNewLineBeforeLeadingComments({ pos: pos, end: pos }, leadingComments, writer);
|
|
|
|
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
|
|
|
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
|
|
|
|
}
|
|
|
|
|
2014-08-19 21:06:52 +02:00
|
|
|
function emitDetachedCommentsAtPosition(node: TextRange) {
|
2014-08-19 19:43:13 +02:00
|
|
|
var leadingComments = getLeadingComments(currentSourceFile.text, node.pos);
|
|
|
|
if (leadingComments) {
|
|
|
|
var detachedComments: Comment[] = [];
|
|
|
|
var lastComment: Comment;
|
|
|
|
|
|
|
|
forEach(leadingComments, comment => {
|
|
|
|
if (lastComment) {
|
2014-08-21 01:50:28 +02:00
|
|
|
var lastCommentLine = getLineOfLocalPosition(lastComment.end);
|
|
|
|
var commentLine = getLineOfLocalPosition(comment.pos);
|
2014-08-19 19:43:13 +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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
detachedComments.push(comment);
|
|
|
|
lastComment = comment;
|
|
|
|
});
|
|
|
|
|
2014-08-22 23:40:47 +02:00
|
|
|
if (detachedComments.length) {
|
2014-08-19 19:43:13 +02:00
|
|
|
// 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-08-21 01:50:28 +02:00
|
|
|
var lastCommentLine = getLineOfLocalPosition(detachedComments[detachedComments.length - 1].end);
|
|
|
|
var astLine = getLineOfLocalPosition(skipTrivia(currentSourceFile.text, node.pos));
|
2014-08-19 19:43:13 +02:00
|
|
|
if (astLine >= lastCommentLine + 2) {
|
|
|
|
// Valid detachedComments
|
2014-08-19 21:06:52 +02:00
|
|
|
emitNewLineBeforeLeadingComments(node, leadingComments, writer);
|
2014-08-19 19:43:13 +02:00
|
|
|
emitComments(detachedComments, /*trailingSeparator*/ true, writer, writeComment);
|
2014-08-19 21:06:52 +02:00
|
|
|
var currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: detachedComments[detachedComments.length - 1].end };
|
|
|
|
if (detachedCommentsInfo) {
|
|
|
|
detachedCommentsInfo.push(currentDetachedCommentInfo);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
detachedCommentsInfo = [currentDetachedCommentInfo];
|
|
|
|
}
|
2014-08-19 19:43:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-22 23:40:47 +02:00
|
|
|
function emitPinnedOrTripleSlashCommentsOfNode(node: Node) {
|
|
|
|
var pinnedComments = ts.filter(getLeadingCommentsToEmit(node), isPinnedOrTripleSlashComment);
|
|
|
|
|
|
|
|
function isPinnedOrTripleSlashComment(comment: Comment) {
|
|
|
|
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 dont 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
emitNewLineBeforeLeadingComments(node, pinnedComments, writer);
|
|
|
|
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
|
|
|
emitComments(pinnedComments, /*trailingSeparator*/ true, writer, writeComment);
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (compilerOptions.sourceMap) {
|
|
|
|
initializeEmitterWithSourceMaps();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (root) {
|
|
|
|
emit(root);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-17 00:39:14 +02:00
|
|
|
forEach(program.getSourceFiles(), sourceFile => {
|
|
|
|
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
|
|
|
|
emit(sourceFile);
|
|
|
|
}
|
|
|
|
});
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
writeLine();
|
2014-08-06 23:24:47 +02:00
|
|
|
writeEmittedFiles(writer.getText(), /*writeByteOrderMark*/ compilerOptions.emitBOM);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitDeclarations(jsFilePath: string, root?: SourceFile) {
|
2014-07-18 23:40:47 +02:00
|
|
|
var writer = createTextWriter(writeSymbol);
|
2014-07-17 00:39:14 +02:00
|
|
|
var write = writer.write;
|
|
|
|
var writeLine = writer.writeLine;
|
|
|
|
var increaseIndent = writer.increaseIndent;
|
|
|
|
var decreaseIndent = writer.decreaseIndent;
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
var enclosingDeclaration: Node;
|
2014-07-19 03:06:37 +02:00
|
|
|
var reportedDeclarationError = false;
|
|
|
|
|
2014-08-14 16:48:14 +02:00
|
|
|
var emitJsDocComments = compilerOptions.removeComments ? function (declaration: Declaration) { } : writeJsDocComments;
|
|
|
|
|
2014-08-05 02:59:33 +02:00
|
|
|
var aliasDeclarationEmitInfo: {
|
|
|
|
declaration: ImportDeclaration;
|
|
|
|
outputPos: number;
|
|
|
|
indent: number;
|
|
|
|
asynchronousOutput?: string; // If the output for alias was written asynchronously, the corresponding output
|
|
|
|
}[] = [];
|
|
|
|
|
2014-07-19 03:06:37 +02:00
|
|
|
var getSymbolVisibilityDiagnosticMessage: (symbolAccesibilityResult: SymbolAccessiblityResult) => {
|
|
|
|
errorNode: Node;
|
|
|
|
diagnosticMessage: DiagnosticMessage;
|
2014-08-07 02:58:03 +02:00
|
|
|
typeName?: Identifier
|
2014-07-19 03:06:37 +02:00
|
|
|
}
|
2014-07-16 19:49:11 +02:00
|
|
|
|
2014-08-08 22:56:53 +02:00
|
|
|
function writeAsychronousImportDeclarations(importDeclarations: ImportDeclaration[]) {
|
|
|
|
var oldWriter = writer;
|
2014-08-14 03:01:58 +02:00
|
|
|
forEach(importDeclarations, aliasToWrite => {
|
2014-08-08 22:56:53 +02:00
|
|
|
var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined);
|
|
|
|
writer = createTextWriter(writeSymbol);
|
|
|
|
for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) {
|
|
|
|
writer.increaseIndent();
|
|
|
|
}
|
|
|
|
|
|
|
|
writeImportDeclaration(aliasToWrite);
|
|
|
|
aliasEmitInfo.asynchronousOutput = writer.getText();
|
|
|
|
});
|
|
|
|
writer = oldWriter;
|
2014-07-19 03:06:37 +02:00
|
|
|
}
|
2014-07-16 19:49:11 +02:00
|
|
|
|
2014-07-18 23:40:47 +02:00
|
|
|
function writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
|
2014-07-19 03:06:37 +02:00
|
|
|
var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning);
|
2014-08-07 03:42:14 +02:00
|
|
|
if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
|
2014-07-19 03:06:37 +02:00
|
|
|
resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer);
|
2014-08-05 02:59:33 +02:00
|
|
|
|
|
|
|
// write the aliases
|
|
|
|
if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) {
|
2014-08-08 22:56:53 +02:00
|
|
|
writeAsychronousImportDeclarations(symbolAccesibilityResult.aliasesToMakeVisible);
|
2014-08-05 02:59:33 +02:00
|
|
|
}
|
2014-07-19 03:06:37 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Report error
|
|
|
|
reportedDeclarationError = true;
|
|
|
|
var errorInfo = getSymbolVisibilityDiagnosticMessage(symbolAccesibilityResult);
|
2014-08-07 02:06:59 +02:00
|
|
|
if (errorInfo) {
|
2014-08-07 02:58:03 +02:00
|
|
|
if (errorInfo.typeName) {
|
|
|
|
diagnostics.push(createDiagnosticForNode(errorInfo.errorNode,
|
|
|
|
errorInfo.diagnosticMessage,
|
|
|
|
getSourceTextOfLocalNode(errorInfo.typeName),
|
|
|
|
symbolAccesibilityResult.errorSymbolName,
|
|
|
|
symbolAccesibilityResult.errorModuleName));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
diagnostics.push(createDiagnosticForNode(errorInfo.errorNode,
|
|
|
|
errorInfo.diagnosticMessage,
|
|
|
|
symbolAccesibilityResult.errorSymbolName,
|
|
|
|
symbolAccesibilityResult.errorModuleName));
|
|
|
|
}
|
2014-08-07 02:06:59 +02:00
|
|
|
}
|
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-07-17 00:39:14 +02:00
|
|
|
function emitLines(nodes: Node[]) {
|
|
|
|
for (var i = 0, n = nodes.length; i < n; i++) {
|
|
|
|
emitNode(nodes[i]);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitCommaList(nodes: Node[], eachNodeEmitFn: (node: Node) => void) {
|
|
|
|
var currentWriterPos = writer.getTextPos();
|
|
|
|
for (var i = 0, n = nodes.length; i < n; i++) {
|
|
|
|
if (currentWriterPos !== writer.getTextPos()) {
|
|
|
|
write(", ");
|
|
|
|
}
|
|
|
|
currentWriterPos = writer.getTextPos();
|
|
|
|
eachNodeEmitFn(nodes[i]);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-14 16:48:14 +02:00
|
|
|
function writeJsDocComments(declaration: Declaration) {
|
2014-08-14 18:01:38 +02:00
|
|
|
if (declaration) {
|
|
|
|
var jsDocComments = getJsDocComments(declaration, currentSourceFile);
|
2014-08-15 23:21:41 +02:00
|
|
|
emitNewLineBeforeLeadingComments(declaration, jsDocComments, writer);
|
2014-08-15 23:32:08 +02:00
|
|
|
// jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space
|
|
|
|
emitComments(jsDocComments, /*trailingSeparator*/ true, writer, writeCommentRange);
|
2014-08-14 18:01:38 +02:00
|
|
|
}
|
2014-08-14 16:48:14 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitSourceTextOfNode(node: Node) {
|
|
|
|
write(getSourceTextOfLocalNode(node));
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitSourceFile(node: SourceFile) {
|
|
|
|
currentSourceFile = node;
|
|
|
|
enclosingDeclaration = node;
|
|
|
|
emitLines(node.statements);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitExportAssignment(node: ExportAssignment) {
|
|
|
|
write("export = ");
|
|
|
|
emitSourceTextOfNode(node.exportName);
|
|
|
|
write(";");
|
|
|
|
writeLine();
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitDeclarationFlags(node: Declaration) {
|
|
|
|
if (node.flags & NodeFlags.Static) {
|
|
|
|
if (node.flags & NodeFlags.Private) {
|
|
|
|
write("private ");
|
|
|
|
}
|
|
|
|
write("static ");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
else {
|
|
|
|
if (node.flags & NodeFlags.Private) {
|
|
|
|
write("private ");
|
|
|
|
}
|
|
|
|
// If the node is parented in the current source file we need to emit export declare or just export
|
|
|
|
else if (node.parent === currentSourceFile) {
|
|
|
|
// If the node is exported
|
|
|
|
if (node.flags & NodeFlags.Export) {
|
|
|
|
write("export ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node.kind !== SyntaxKind.InterfaceDeclaration) {
|
|
|
|
write("declare ");
|
|
|
|
}
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function emitImportDeclaration(node: ImportDeclaration) {
|
2014-08-05 02:59:33 +02:00
|
|
|
var nodeEmitInfo = {
|
|
|
|
declaration: node,
|
|
|
|
outputPos: writer.getTextPos(),
|
|
|
|
indent: writer.getIndent(),
|
|
|
|
hasWritten: resolver.isDeclarationVisible(node)
|
|
|
|
};
|
|
|
|
aliasDeclarationEmitInfo.push(nodeEmitInfo);
|
|
|
|
if (nodeEmitInfo.hasWritten) {
|
|
|
|
writeImportDeclaration(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function writeImportDeclaration(node: ImportDeclaration) {
|
|
|
|
// note usage of writer. methods instead of aliases created, just to make sure we are using
|
|
|
|
// correct writer especially to handle asynchronous alias writing
|
2014-08-14 16:48:14 +02:00
|
|
|
emitJsDocComments(node);
|
2014-08-05 02:59:33 +02:00
|
|
|
if (node.flags & NodeFlags.Export) {
|
|
|
|
writer.write("export ");
|
|
|
|
}
|
|
|
|
writer.write("import ");
|
|
|
|
writer.write(getSourceTextOfLocalNode(node.name));
|
|
|
|
writer.write(" = ");
|
|
|
|
if (node.entityName) {
|
2014-08-08 22:56:53 +02:00
|
|
|
checkEntityNameAccessible();
|
2014-08-05 02:59:33 +02:00
|
|
|
writer.write(getSourceTextOfLocalNode(node.entityName));
|
|
|
|
writer.write(";");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
writer.write("require(");
|
|
|
|
writer.write(getSourceTextOfLocalNode(node.externalModuleName));
|
|
|
|
writer.write(");");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-08-05 02:59:33 +02:00
|
|
|
writer.writeLine();
|
2014-08-08 22:56:53 +02:00
|
|
|
|
|
|
|
function checkEntityNameAccessible() {
|
|
|
|
var symbolAccesibilityResult = resolver.isImportDeclarationEntityNameReferenceDeclarationVisibile(node.entityName);
|
|
|
|
if (symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
|
|
|
|
// write the aliases
|
|
|
|
if (symbolAccesibilityResult.aliasesToMakeVisible) {
|
|
|
|
writeAsychronousImportDeclarations(symbolAccesibilityResult.aliasesToMakeVisible);
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-08-08 22:56:53 +02:00
|
|
|
// Report error
|
|
|
|
reportedDeclarationError = true;
|
|
|
|
diagnostics.push(createDiagnosticForNode(node,
|
|
|
|
Diagnostics.Import_declaration_0_is_using_private_name_1,
|
|
|
|
getSourceTextOfLocalNode(node.name),
|
|
|
|
symbolAccesibilityResult.errorSymbolName));
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-10 01:12:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitModuleDeclaration(node: ModuleDeclaration) {
|
|
|
|
if (resolver.isDeclarationVisible(node)) {
|
2014-08-14 16:56:46 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitDeclarationFlags(node);
|
|
|
|
write("module ");
|
|
|
|
emitSourceTextOfNode(node.name);
|
|
|
|
while (node.body.kind !== SyntaxKind.ModuleBlock) {
|
|
|
|
node = <ModuleDeclaration>node.body;
|
|
|
|
write(".");
|
|
|
|
emitSourceTextOfNode(node.name);
|
|
|
|
}
|
|
|
|
var prevEnclosingDeclaration = enclosingDeclaration;
|
|
|
|
enclosingDeclaration = node;
|
|
|
|
write(" {");
|
|
|
|
writeLine();
|
|
|
|
increaseIndent();
|
|
|
|
emitLines((<Block>node.body).statements);
|
|
|
|
decreaseIndent();
|
|
|
|
write("}");
|
|
|
|
writeLine();
|
|
|
|
enclosingDeclaration = prevEnclosingDeclaration;
|
2014-07-10 01:12:16 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
|
|
|
|
function emitEnumDeclaration(node: EnumDeclaration) {
|
|
|
|
if (resolver.isDeclarationVisible(node)) {
|
2014-08-14 16:59:41 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitDeclarationFlags(node);
|
|
|
|
write("enum ");
|
2014-07-13 01:04:16 +02:00
|
|
|
emitSourceTextOfNode(node.name);
|
2014-07-17 00:39:14 +02:00
|
|
|
write(" {");
|
|
|
|
writeLine();
|
|
|
|
increaseIndent();
|
|
|
|
emitLines(node.members);
|
|
|
|
decreaseIndent();
|
|
|
|
write("}");
|
|
|
|
writeLine();
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitEnumMemberDeclaration(node: EnumMember) {
|
2014-08-14 17:02:03 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
emitSourceTextOfNode(node.name);
|
2014-07-17 00:39:14 +02:00
|
|
|
var enumMemberValue = resolver.getEnumMemberValue(node);
|
|
|
|
if (enumMemberValue !== undefined) {
|
|
|
|
write(" = ");
|
|
|
|
write(enumMemberValue.toString());
|
|
|
|
}
|
|
|
|
write(",");
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitTypeParameters(typeParameters: TypeParameterDeclaration[]) {
|
|
|
|
function emitTypeParameter(node: TypeParameterDeclaration) {
|
2014-07-19 03:11:04 +02:00
|
|
|
function getTypeParameterConstraintVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
|
2014-08-11 23:15:57 +02:00
|
|
|
// Type parameter constraints are named by user so we should always be able to name it
|
2014-07-19 03:11:04 +02:00
|
|
|
var diagnosticMessage: DiagnosticMessage;
|
|
|
|
switch (node.parent.kind) {
|
|
|
|
case SyntaxKind.ClassDeclaration:
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-04 21:06:07 +02:00
|
|
|
Diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_private_name_1;
|
2014-07-19 03:11:04 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.InterfaceDeclaration:
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-04 21:06:07 +02:00
|
|
|
Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1;
|
2014-07-19 03:11:04 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.ConstructSignature:
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-04 21:06:07 +02:00
|
|
|
Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
|
2014-07-19 03:11:04 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.CallSignature:
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-04 21:06:07 +02:00
|
|
|
Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
|
2014-07-19 03:11:04 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.Method:
|
|
|
|
if (node.parent.flags & NodeFlags.Static) {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-04 21:06:07 +02:00
|
|
|
Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
|
2014-07-19 03:11:04 +02:00
|
|
|
}
|
|
|
|
else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-04 21:06:07 +02:00
|
|
|
Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
|
2014-07-19 03:11:04 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-04 21:06:07 +02:00
|
|
|
Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
|
2014-07-19 03:11:04 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.FunctionDeclaration:
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-04 21:06:07 +02:00
|
|
|
Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1;
|
2014-07-19 03:11:04 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Debug.fail("This is unknown parent for type parameter: " + SyntaxKind[node.parent.kind]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
diagnosticMessage: diagnosticMessage,
|
|
|
|
errorNode: node,
|
|
|
|
typeName: node.name
|
2014-08-04 21:30:46 +02:00
|
|
|
};
|
2014-07-19 03:11:04 +02:00
|
|
|
}
|
|
|
|
|
2014-08-14 18:38:22 +02:00
|
|
|
increaseIndent();
|
2014-08-14 17:23:42 +02:00
|
|
|
emitJsDocComments(node);
|
2014-08-14 18:38:22 +02:00
|
|
|
decreaseIndent();
|
2014-07-17 00:39:14 +02:00
|
|
|
emitSourceTextOfNode(node.name);
|
2014-08-04 21:06:07 +02:00
|
|
|
// If there is constraint present and this is not a type parameter of the private method emit the constraint
|
|
|
|
if (node.constraint && (node.parent.kind !== SyntaxKind.Method || !(node.parent.flags & NodeFlags.Private))) {
|
2014-07-17 00:39:14 +02:00
|
|
|
write(" extends ");
|
2014-07-19 03:11:04 +02:00
|
|
|
getSymbolVisibilityDiagnosticMessage = getTypeParameterConstraintVisibilityError;
|
2014-08-09 01:15:09 +02:00
|
|
|
resolver.writeTypeAtLocation(node.constraint, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (typeParameters) {
|
|
|
|
write("<");
|
|
|
|
emitCommaList(typeParameters, emitTypeParameter);
|
|
|
|
write(">");
|
|
|
|
}
|
2014-07-12 00:13:01 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitHeritageClause(typeReferences: TypeReferenceNode[], isImplementsList: boolean) {
|
|
|
|
if (typeReferences) {
|
2014-07-17 22:01:23 +02:00
|
|
|
write(isImplementsList ? " implements " : " extends ");
|
2014-07-17 00:39:14 +02:00
|
|
|
emitCommaList(typeReferences, emitTypeOfTypeReference);
|
|
|
|
}
|
2014-08-04 21:06:07 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitTypeOfTypeReference(node: Node) {
|
2014-08-04 21:06:07 +02:00
|
|
|
getSymbolVisibilityDiagnosticMessage = getHeritageClauseVisibilityError;
|
2014-08-09 01:15:09 +02:00
|
|
|
resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.WriteArrayAsGenericType | TypeFormatFlags.UseTypeOfFunction, writer);
|
2014-08-04 21:06:07 +02:00
|
|
|
|
2014-07-19 03:07:38 +02:00
|
|
|
function getHeritageClauseVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
|
|
|
|
var diagnosticMessage: DiagnosticMessage;
|
2014-08-11 23:15:57 +02:00
|
|
|
// Heritage clause is written by user so it can always be named
|
2014-07-19 03:07:38 +02:00
|
|
|
if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
|
|
|
// Class
|
2014-08-11 23:15:57 +02:00
|
|
|
if (symbolAccesibilityResult.errorModuleName) {
|
|
|
|
// Module is inaccessible
|
|
|
|
diagnosticMessage = isImplementsList ?
|
|
|
|
Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_name_1_from_private_module_2 :
|
|
|
|
Diagnostics.Extends_clause_of_exported_class_0_has_or_is_using_name_1_from_private_module_2;
|
2014-07-19 03:07:38 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-08-11 23:15:57 +02:00
|
|
|
// Class or Interface implemented/extended is inaccessible
|
|
|
|
diagnosticMessage = isImplementsList ?
|
|
|
|
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-19 03:07:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2014-08-11 23:15:57 +02:00
|
|
|
if (symbolAccesibilityResult.errorModuleName) {
|
|
|
|
// Module is inaccessible
|
|
|
|
diagnosticMessage = Diagnostics.Extends_clause_of_exported_interface_0_has_or_is_using_name_1_from_private_module_2;
|
2014-07-19 03:07:38 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-08-11 23:15:57 +02:00
|
|
|
// interface is inaccessible
|
|
|
|
diagnosticMessage = Diagnostics.Extends_clause_of_exported_interface_0_has_or_is_using_private_name_1;
|
2014-07-19 03:07:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
diagnosticMessage: diagnosticMessage,
|
|
|
|
errorNode: node,
|
|
|
|
typeName: (<Declaration>node.parent).name
|
2014-08-04 21:30:46 +02:00
|
|
|
};
|
2014-07-19 03:07:38 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
2014-07-12 01:36:06 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitClassDeclaration(node: ClassDeclaration) {
|
|
|
|
function emitParameterProperties(constructorDeclaration: ConstructorDeclaration) {
|
|
|
|
if (constructorDeclaration) {
|
|
|
|
forEach(constructorDeclaration.parameters, param => {
|
|
|
|
if (param.flags & (NodeFlags.Public | NodeFlags.Private)) {
|
|
|
|
emitPropertyDeclaration(param);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (resolver.isDeclarationVisible(node)) {
|
2014-08-14 17:47:21 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitDeclarationFlags(node);
|
|
|
|
write("class ");
|
|
|
|
emitSourceTextOfNode(node.name);
|
|
|
|
var prevEnclosingDeclaration = enclosingDeclaration;
|
|
|
|
enclosingDeclaration = node;
|
|
|
|
emitTypeParameters(node.typeParameters);
|
|
|
|
if (node.baseType) {
|
|
|
|
emitHeritageClause([node.baseType], /*isImplementsList*/ false);
|
|
|
|
}
|
|
|
|
emitHeritageClause(node.implementedTypes, /*isImplementsList*/ true);
|
|
|
|
write(" {");
|
|
|
|
writeLine();
|
|
|
|
increaseIndent();
|
|
|
|
emitParameterProperties(getFirstConstructorWithBody(node));
|
|
|
|
emitLines(node.members);
|
|
|
|
decreaseIndent();
|
|
|
|
write("}");
|
|
|
|
writeLine();
|
|
|
|
enclosingDeclaration = prevEnclosingDeclaration;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitInterfaceDeclaration(node: InterfaceDeclaration) {
|
|
|
|
if (resolver.isDeclarationVisible(node)) {
|
2014-08-14 17:50:17 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitDeclarationFlags(node);
|
|
|
|
write("interface ");
|
|
|
|
emitSourceTextOfNode(node.name);
|
|
|
|
var prevEnclosingDeclaration = enclosingDeclaration;
|
|
|
|
enclosingDeclaration = node;
|
|
|
|
emitTypeParameters(node.typeParameters);
|
|
|
|
emitHeritageClause(node.baseTypes, /*isImplementsList*/ false);
|
|
|
|
write(" {");
|
|
|
|
writeLine();
|
|
|
|
increaseIndent();
|
|
|
|
emitLines(node.members);
|
|
|
|
decreaseIndent();
|
|
|
|
write("}");
|
|
|
|
writeLine();
|
|
|
|
enclosingDeclaration = prevEnclosingDeclaration;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitPropertyDeclaration(node: PropertyDeclaration) {
|
2014-08-14 17:53:02 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
emitDeclarationFlags(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitVariableDeclaration(node);
|
|
|
|
write(";");
|
2014-07-13 01:04:16 +02:00
|
|
|
writeLine();
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitVariableDeclaration(node: VariableDeclaration) {
|
|
|
|
// If we are emitting property it isnt 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)) {
|
|
|
|
emitSourceTextOfNode(node.name);
|
|
|
|
// If optional property emit ?
|
|
|
|
if (node.kind === SyntaxKind.Property && (node.flags & NodeFlags.QuestionMark)) {
|
|
|
|
write("?");
|
|
|
|
}
|
|
|
|
if (!(node.flags & NodeFlags.Private)) {
|
|
|
|
write(": ");
|
2014-08-04 21:30:46 +02:00
|
|
|
getSymbolVisibilityDiagnosticMessage = getVariableDeclarationTypeVisibilityError;
|
2014-08-09 01:15:09 +02:00
|
|
|
resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
2014-07-12 00:13:01 +02:00
|
|
|
}
|
2014-08-04 21:30:46 +02:00
|
|
|
|
|
|
|
function getVariableDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
|
|
|
|
var diagnosticMessage: DiagnosticMessage;
|
|
|
|
if (node.kind === SyntaxKind.VariableDeclaration) {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
|
|
|
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
2014-08-04 21:30:46 +02:00
|
|
|
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;
|
|
|
|
}
|
2014-08-07 02:06:59 +02:00
|
|
|
// This check is to ensure we dont report error on constructor parameter property as that error would be reported during parameter emit
|
|
|
|
else if (node.kind === SyntaxKind.Property) {
|
2014-08-07 00:17:44 +02:00
|
|
|
if (node.flags & NodeFlags.Static) {
|
2014-08-04 21:30:46 +02:00
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-04 21:30:46 +02:00
|
|
|
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-08-07 00:17:44 +02:00
|
|
|
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
2014-08-04 21:30:46 +02:00
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-04 21:30:46 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
else {
|
2014-08-11 23:15:57 +02:00
|
|
|
// Interfaces cannot have types that cannot be named
|
2014-08-04 21:30:46 +02:00
|
|
|
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-08-04 21:30:46 +02:00
|
|
|
|
2014-08-07 02:06:59 +02:00
|
|
|
return diagnosticMessage !== undefined ? {
|
2014-08-04 21:30:46 +02:00
|
|
|
diagnosticMessage: diagnosticMessage,
|
|
|
|
errorNode: node,
|
|
|
|
typeName: node.name
|
2014-08-07 02:06:59 +02:00
|
|
|
} : undefined;
|
2014-07-12 00:13:01 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitVariableStatement(node: VariableStatement) {
|
|
|
|
var hasDeclarationWithEmit = forEach(node.declarations, varDeclaration => resolver.isDeclarationVisible(varDeclaration));
|
|
|
|
if (hasDeclarationWithEmit) {
|
2014-08-14 17:57:28 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitDeclarationFlags(node);
|
|
|
|
write("var ");
|
|
|
|
emitCommaList(node.declarations, emitVariableDeclaration);
|
|
|
|
write(";");
|
|
|
|
writeLine();
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitAccessorDeclaration(node: AccessorDeclaration) {
|
|
|
|
var accessors = getAllAccessorDeclarations(<ClassDeclaration>node.parent, node);
|
|
|
|
if (node === accessors.firstAccessor) {
|
2014-08-14 18:01:38 +02:00
|
|
|
emitJsDocComments(accessors.getAccessor);
|
|
|
|
emitJsDocComments(accessors.setAccessor);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitDeclarationFlags(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
emitSourceTextOfNode(node.name);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (!(node.flags & NodeFlags.Private)) {
|
|
|
|
write(": ");
|
2014-08-07 03:42:14 +02:00
|
|
|
getSymbolVisibilityDiagnosticMessage = getAccessorDeclarationTypeVisibilityError;
|
2014-08-09 01:15:09 +02:00
|
|
|
resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
write(";");
|
|
|
|
writeLine();
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-08-07 03:42:14 +02:00
|
|
|
|
|
|
|
function getAccessorDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
|
|
|
|
var diagnosticMessage: DiagnosticMessage;
|
|
|
|
if (node.kind === SyntaxKind.SetAccessor) {
|
2014-08-11 23:15:57 +02:00
|
|
|
// Setters have to have type named and cannot infer it so, the type should always be named
|
2014-08-07 03:42:14 +02:00
|
|
|
if (node.parent.flags & NodeFlags.Static) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
diagnosticMessage: diagnosticMessage,
|
|
|
|
errorNode: node.parameters[0],
|
|
|
|
typeName: node.name
|
|
|
|
};
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (node.flags & NodeFlags.Static) {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-07 03:42:14 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-07 03:42:14 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
diagnosticMessage: diagnosticMessage,
|
|
|
|
errorNode: node.name,
|
|
|
|
typeName: undefined
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function emitFunctionDeclaration(node: FunctionDeclaration) {
|
|
|
|
// If we are emitting Method/Constructor it isnt 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)) {
|
2014-08-14 18:08:53 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
emitDeclarationFlags(node);
|
|
|
|
if (node.kind === SyntaxKind.FunctionDeclaration) {
|
|
|
|
write("function ");
|
|
|
|
emitSourceTextOfNode(node.name);
|
|
|
|
}
|
|
|
|
else if (node.kind === SyntaxKind.Constructor) {
|
|
|
|
write("constructor");
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
else {
|
|
|
|
emitSourceTextOfNode(node.name);
|
|
|
|
if (node.flags & NodeFlags.QuestionMark) {
|
|
|
|
write("?");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
emitSignatureDeclaration(node);
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function emitConstructSignatureDeclaration(node: SignatureDeclaration) {
|
2014-08-14 18:12:20 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
write("new ");
|
2014-07-13 01:04:16 +02:00
|
|
|
emitSignatureDeclaration(node);
|
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitSignatureDeclaration(node: SignatureDeclaration) {
|
2014-08-14 18:12:20 +02:00
|
|
|
if (node.kind === SyntaxKind.CallSignature || node.kind === SyntaxKind.IndexSignature) {
|
|
|
|
// Only index and call signatures are emitted directly, so emit their js doc comments, rest will do that in their own functions
|
|
|
|
emitJsDocComments(node);
|
|
|
|
}
|
2014-07-17 00:39:14 +02:00
|
|
|
emitTypeParameters(node.typeParameters);
|
|
|
|
if (node.kind === SyntaxKind.IndexSignature) {
|
|
|
|
write("[");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write("(");
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// Parameters
|
|
|
|
emitCommaList(node.parameters, emitParameterDeclaration);
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (node.kind === SyntaxKind.IndexSignature) {
|
|
|
|
write("]");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write(")");
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// If this is not a constructor and is not private, emit the return type
|
|
|
|
if (node.kind !== SyntaxKind.Constructor && !(node.flags & NodeFlags.Private)) {
|
|
|
|
write(": ");
|
2014-08-07 02:58:03 +02:00
|
|
|
getSymbolVisibilityDiagnosticMessage = getReturnTypeVisibilityError;
|
2014-08-09 01:15:09 +02:00
|
|
|
resolver.writeReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
|
|
|
write(";");
|
|
|
|
writeLine();
|
2014-08-07 02:58:03 +02:00
|
|
|
|
|
|
|
function getReturnTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
|
|
|
|
var diagnosticMessage: DiagnosticMessage;
|
|
|
|
switch (node.kind) {
|
|
|
|
case SyntaxKind.ConstructSignature:
|
2014-08-11 23:15:57 +02:00
|
|
|
// Interfaces cannot have return types that cannot be named
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-07 02:58:03 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
case SyntaxKind.CallSignature:
|
2014-08-11 23:15:57 +02:00
|
|
|
// Interfaces cannot have return types that cannot be named
|
2014-08-07 02:58:03 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
case SyntaxKind.IndexSignature:
|
2014-08-11 23:15:57 +02:00
|
|
|
// Interfaces cannot have return types that cannot be named
|
2014-08-07 02:58:03 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
case SyntaxKind.Method:
|
|
|
|
if (node.flags & NodeFlags.Static) {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-07 02:58:03 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-07 02:58:03 +02:00
|
|
|
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 {
|
2014-08-11 23:15:57 +02:00
|
|
|
// Interfaces cannot have return types that cannot be named
|
2014-08-07 02:58:03 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
case SyntaxKind.FunctionDeclaration:
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
|
|
|
Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
|
2014-08-07 02:58:03 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Debug.fail("This is unknown kind for signature: " + SyntaxKind[node.kind]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
diagnosticMessage: diagnosticMessage,
|
|
|
|
errorNode: <Node>node.name || node,
|
|
|
|
};
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitParameterDeclaration(node: ParameterDeclaration) {
|
2014-08-14 18:38:22 +02:00
|
|
|
increaseIndent();
|
2014-08-14 18:35:58 +02:00
|
|
|
emitJsDocComments(node);
|
2014-07-17 00:39:14 +02:00
|
|
|
if (node.flags & NodeFlags.Rest) {
|
|
|
|
write("...");
|
|
|
|
}
|
|
|
|
emitSourceTextOfNode(node.name);
|
|
|
|
if (node.initializer || (node.flags & NodeFlags.QuestionMark)) {
|
|
|
|
write("?");
|
|
|
|
}
|
2014-08-14 18:38:22 +02:00
|
|
|
decreaseIndent();
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (!(node.parent.flags & NodeFlags.Private)) {
|
|
|
|
write(": ");
|
2014-08-07 02:06:59 +02:00
|
|
|
getSymbolVisibilityDiagnosticMessage = getParameterDeclarationTypeVisibilityError;
|
2014-08-09 01:15:09 +02:00
|
|
|
resolver.writeTypeAtLocation(node, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
|
2014-08-07 02:06:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function getParameterDeclarationTypeVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
|
|
|
|
var diagnosticMessage: DiagnosticMessage;
|
|
|
|
switch (node.parent.kind) {
|
|
|
|
case SyntaxKind.Constructor:
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-07 02:06:59 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
case SyntaxKind.ConstructSignature:
|
2014-08-11 23:15:57 +02:00
|
|
|
// Interfaces cannot have parameter types that cannot be named
|
2014-08-07 02:06:59 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
case SyntaxKind.CallSignature:
|
2014-08-11 23:15:57 +02:00
|
|
|
// Interfaces cannot have parameter types that cannot be named
|
2014-08-07 02:06:59 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
case SyntaxKind.Method:
|
|
|
|
if (node.parent.flags & NodeFlags.Static) {
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-07 02:06:59 +02:00
|
|
|
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 ?
|
2014-08-11 23:15:57 +02:00
|
|
|
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 :
|
2014-08-07 02:06:59 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
else {
|
2014-08-11 23:15:57 +02:00
|
|
|
// Interfaces cannot have parameter types that cannot be named
|
2014-08-07 02:06:59 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SyntaxKind.FunctionDeclaration:
|
|
|
|
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
2014-08-11 23:15:57 +02:00
|
|
|
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
|
|
|
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
2014-08-07 02:06:59 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Debug.fail("This is unknown parent for parameter: " + SyntaxKind[node.parent.kind]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
diagnosticMessage: diagnosticMessage,
|
|
|
|
errorNode: node,
|
|
|
|
typeName: node.name
|
|
|
|
};
|
2014-07-17 00:39:14 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
function emitNode(node: Node) {
|
|
|
|
switch (node.kind) {
|
|
|
|
case SyntaxKind.Constructor:
|
|
|
|
case SyntaxKind.FunctionDeclaration:
|
|
|
|
case SyntaxKind.Method:
|
|
|
|
return emitFunctionDeclaration(<FunctionDeclaration>node);
|
|
|
|
case SyntaxKind.ConstructSignature:
|
|
|
|
return emitConstructSignatureDeclaration(<SignatureDeclaration>node);
|
|
|
|
case SyntaxKind.CallSignature:
|
|
|
|
case SyntaxKind.IndexSignature:
|
|
|
|
return emitSignatureDeclaration(<SignatureDeclaration>node);
|
|
|
|
case SyntaxKind.GetAccessor:
|
|
|
|
case SyntaxKind.SetAccessor:
|
|
|
|
return emitAccessorDeclaration(<AccessorDeclaration>node);
|
|
|
|
case SyntaxKind.VariableStatement:
|
|
|
|
return emitVariableStatement(<VariableStatement>node);
|
|
|
|
case SyntaxKind.Property:
|
|
|
|
return emitPropertyDeclaration(<PropertyDeclaration>node);
|
|
|
|
case SyntaxKind.InterfaceDeclaration:
|
|
|
|
return emitInterfaceDeclaration(<InterfaceDeclaration>node);
|
|
|
|
case SyntaxKind.ClassDeclaration:
|
|
|
|
return emitClassDeclaration(<ClassDeclaration>node);
|
|
|
|
case SyntaxKind.EnumMember:
|
|
|
|
return emitEnumMemberDeclaration(<EnumMember>node);
|
|
|
|
case SyntaxKind.EnumDeclaration:
|
|
|
|
return emitEnumDeclaration(<EnumDeclaration>node);
|
|
|
|
case SyntaxKind.ModuleDeclaration:
|
|
|
|
return emitModuleDeclaration(<ModuleDeclaration>node);
|
|
|
|
case SyntaxKind.ImportDeclaration:
|
|
|
|
return emitImportDeclaration(<ImportDeclaration>node);
|
|
|
|
case SyntaxKind.ExportAssignment:
|
|
|
|
return emitExportAssignment(<ExportAssignment>node);
|
|
|
|
case SyntaxKind.SourceFile:
|
|
|
|
return emitSourceFile(<SourceFile>node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function resolveScriptReference(sourceFile: SourceFile, reference: FileReference) {
|
|
|
|
var referenceFileName = compilerOptions.noResolve
|
|
|
|
? reference.filename
|
|
|
|
: normalizePath(combinePaths(getDirectoryPath(sourceFile.filename), reference.filename));
|
|
|
|
return program.getSourceFile(referenceFileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 = "";
|
|
|
|
function writeReferencePath(referencedFile: SourceFile) {
|
|
|
|
var declFileName = referencedFile.flags & NodeFlags.DeclarationFile
|
|
|
|
? referencedFile.filename // Declaration file, use declaration file name
|
2014-07-17 21:53:07 +02:00
|
|
|
: shouldEmitToOwnFile(referencedFile)
|
2014-07-17 00:39:14 +02:00
|
|
|
? getOwnEmitOutputFilePath(referencedFile, ".d.ts") // Own output file so get the .d.ts file
|
|
|
|
: getModuleNameFromFilename(compilerOptions.out) + ".d.ts";// Global out file
|
|
|
|
|
|
|
|
declFileName = getRelativePathToDirectoryOrUrl(
|
|
|
|
getDirectoryPath(normalizeSlashes(jsFilePath)),
|
|
|
|
declFileName,
|
|
|
|
compilerHost.getCurrentDirectory(),
|
|
|
|
/*isAbsolutePathAnUrl*/ false);
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-19 02:46:41 +02:00
|
|
|
referencePathsOutput += "/// <reference path='" + declFileName + "' />" + newLine;
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
if (root) {
|
|
|
|
// Emiting single file so emit references in this file only
|
|
|
|
var addedGlobalFileReference = false;
|
|
|
|
forEach(root.referencedFiles, fileReference => {
|
|
|
|
var referencedFile = resolveScriptReference(root, fileReference);
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
// All the references that are not going to be part of same file
|
|
|
|
if ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference
|
2014-07-17 21:53:07 +02:00
|
|
|
shouldEmitToOwnFile(referencedFile) || // This is referenced file is emitting its own js file
|
2014-07-17 00:39:14 +02:00
|
|
|
!addedGlobalFileReference) { // Or the global out file corresponding to this reference was not added
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
writeReferencePath(referencedFile);
|
|
|
|
if (!isExternalModuleOrDeclarationFile(referencedFile)) {
|
|
|
|
addedGlobalFileReference = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
emitNode(root);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Emit references corresponding to this file
|
|
|
|
var emittedReferencedFiles: SourceFile[] = [];
|
|
|
|
forEach(program.getSourceFiles(), sourceFile => {
|
|
|
|
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
|
|
|
|
// Check what references need to be added
|
|
|
|
forEach(sourceFile.referencedFiles, fileReference => {
|
|
|
|
var referencedFile = resolveScriptReference(sourceFile, fileReference);
|
|
|
|
|
|
|
|
// If the reference file is declaration file or external module emit that reference
|
|
|
|
if (isExternalModuleOrDeclarationFile(referencedFile) &&
|
|
|
|
!contains(emittedReferencedFiles, referencedFile)) { // If the file refernece was not already emitted
|
|
|
|
|
|
|
|
writeReferencePath(referencedFile);
|
|
|
|
emittedReferencedFiles.push(referencedFile);
|
|
|
|
}
|
|
|
|
});
|
2014-07-13 01:04:16 +02:00
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
emitNode(sourceFile);
|
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-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
|
|
|
|
if (!reportedDeclarationError) {
|
2014-08-05 02:59:33 +02:00
|
|
|
var declarationOutput = referencePathsOutput;
|
|
|
|
var synchronousDeclarationOutput = writer.getText();
|
|
|
|
// apply additions
|
|
|
|
var appliedSyncOutputPos = 0;
|
|
|
|
forEach(aliasDeclarationEmitInfo, aliasEmitInfo => {
|
|
|
|
if (aliasEmitInfo.asynchronousOutput) {
|
|
|
|
declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos, aliasEmitInfo.outputPos);
|
|
|
|
declarationOutput += aliasEmitInfo.asynchronousOutput;
|
|
|
|
appliedSyncOutputPos = aliasEmitInfo.outputPos;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos);
|
2014-08-14 03:48:05 +02:00
|
|
|
writeFile(getModuleNameFromFilename(jsFilePath) + ".d.ts", declarationOutput, compilerOptions.emitBOM);
|
2014-07-19 03:06:37 +02:00
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
var shouldEmitDeclarations = resolver.shouldEmitDeclarations();
|
|
|
|
function emitFile(jsFilePath: string, sourceFile?: SourceFile) {
|
|
|
|
emitJavaScript(jsFilePath, sourceFile);
|
|
|
|
if (shouldEmitDeclarations) {
|
|
|
|
emitDeclarations(jsFilePath, sourceFile);
|
|
|
|
}
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
forEach(program.getSourceFiles(), sourceFile => {
|
2014-07-17 21:53:07 +02:00
|
|
|
if (shouldEmitToOwnFile(sourceFile)) {
|
2014-07-17 00:39:14 +02:00
|
|
|
var jsFilePath = getOwnEmitOutputFilePath(sourceFile, ".js");
|
|
|
|
emitFile(jsFilePath, sourceFile);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (compilerOptions.out) {
|
|
|
|
emitFile(compilerOptions.out);
|
|
|
|
}
|
2014-08-04 21:30:46 +02:00
|
|
|
|
|
|
|
// Sort and make the unique list of diagnostics
|
|
|
|
diagnostics.sort(compareDiagnostics);
|
|
|
|
diagnostics = deduplicateSortedDiagnostics(diagnostics);
|
|
|
|
|
2014-07-17 00:39:14 +02:00
|
|
|
return {
|
|
|
|
errors: diagnostics,
|
|
|
|
sourceMaps: sourceMapDataList
|
|
|
|
};
|
2014-07-13 01:04:16 +02:00
|
|
|
}
|
|
|
|
}
|