mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
5230 lines
263 KiB
TypeScript
5230 lines
263 KiB
TypeScript
/// <reference path="checker.ts"/>
|
|
/// <reference path="declarationEmitter.ts"/>
|
|
/* @internal */
|
|
var ts;
|
|
(function (ts) {
|
|
function isExternalModuleOrDeclarationFile(sourceFile) {
|
|
return ts.isExternalModule(sourceFile) || ts.isDeclarationFile(sourceFile);
|
|
}
|
|
ts.isExternalModuleOrDeclarationFile = isExternalModuleOrDeclarationFile;
|
|
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
|
|
function emitFiles(resolver, host, targetSourceFile) {
|
|
// emit output for the __extends helper function
|
|
var extendsHelper = "\nvar __extends = this.__extends || function (d, b) {\n for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];\n function __() { this.constructor = d; }\n __.prototype = b.prototype;\n d.prototype = new __();\n};";
|
|
// emit output for the __decorate helper function
|
|
var decorateHelper = "\nvar __decorate = this.__decorate || (typeof Reflect === \"object\" && Reflect.decorate) || function (decorators, target, key, desc) {\n switch (arguments.length) {\n case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target);\n case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0);\n case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc);\n }\n};";
|
|
// emit output for the __metadata helper function
|
|
var metadataHelper = "\nvar __metadata = this.__metadata || (typeof Reflect === \"object\" && Reflect.metadata) || function () { };";
|
|
// emit output for the __param helper function
|
|
var paramHelper = "\nvar __param = this.__param || function(index, decorator) { return function (target, key) { decorator(target, key, index); } };";
|
|
var compilerOptions = host.getCompilerOptions();
|
|
var languageVersion = compilerOptions.target || 0 /* ES3 */;
|
|
var sourceMapDataList = compilerOptions.sourceMap ? [] : undefined;
|
|
var diagnostics = [];
|
|
var newLine = host.getNewLine();
|
|
if (targetSourceFile === undefined) {
|
|
ts.forEach(host.getSourceFiles(), function (sourceFile) {
|
|
if (ts.shouldEmitToOwnFile(sourceFile, compilerOptions)) {
|
|
var jsFilePath = ts.getOwnEmitOutputFilePath(sourceFile, host, ".js");
|
|
emitFile(jsFilePath, sourceFile);
|
|
}
|
|
});
|
|
if (compilerOptions.out) {
|
|
emitFile(compilerOptions.out);
|
|
}
|
|
}
|
|
else {
|
|
// targetSourceFile is specified (e.g calling emitter from language service or calling getSemanticDiagnostic from language service)
|
|
if (ts.shouldEmitToOwnFile(targetSourceFile, compilerOptions)) {
|
|
var jsFilePath = ts.getOwnEmitOutputFilePath(targetSourceFile, host, ".js");
|
|
emitFile(jsFilePath, targetSourceFile);
|
|
}
|
|
else if (!ts.isDeclarationFile(targetSourceFile) && compilerOptions.out) {
|
|
emitFile(compilerOptions.out);
|
|
}
|
|
}
|
|
// Sort and make the unique list of diagnostics
|
|
diagnostics = ts.sortAndDeduplicateDiagnostics(diagnostics);
|
|
return {
|
|
emitSkipped: false,
|
|
diagnostics: diagnostics,
|
|
sourceMaps: sourceMapDataList
|
|
};
|
|
function isNodeDescendentOf(node, ancestor) {
|
|
while (node) {
|
|
if (node === ancestor)
|
|
return true;
|
|
node = node.parent;
|
|
}
|
|
return false;
|
|
}
|
|
function isUniqueLocalName(name, container) {
|
|
for (var node = container; isNodeDescendentOf(node, container); node = node.nextContainer) {
|
|
if (node.locals && ts.hasProperty(node.locals, name)) {
|
|
// We conservatively include alias symbols to cover cases where they're emitted as locals
|
|
if (node.locals[name].flags & (107455 /* Value */ | 1048576 /* ExportValue */ | 8388608 /* Alias */)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function emitJavaScript(jsFilePath, root) {
|
|
var writer = ts.createTextWriter(newLine);
|
|
var write = writer.write;
|
|
var writeTextOfNode = writer.writeTextOfNode;
|
|
var writeLine = writer.writeLine;
|
|
var increaseIndent = writer.increaseIndent;
|
|
var decreaseIndent = writer.decreaseIndent;
|
|
var currentSourceFile;
|
|
// name of an exporter function if file is a System external module
|
|
// System.register([...], function (<exporter>) {...})
|
|
// exporting in System modules looks like:
|
|
// export var x; ... x = 1
|
|
// =>
|
|
// var x;... exporter("x", x = 1)
|
|
var exportFunctionForFile;
|
|
var generatedNameSet = {};
|
|
var nodeToGeneratedName = [];
|
|
var blockScopedVariableToGeneratedName;
|
|
var computedPropertyNamesToGeneratedNames;
|
|
var extendsEmitted = false;
|
|
var decorateEmitted = false;
|
|
var paramEmitted = false;
|
|
var tempFlags = 0;
|
|
var tempVariables;
|
|
var tempParameters;
|
|
var externalImports;
|
|
var exportSpecifiers;
|
|
var exportEquals;
|
|
var hasExportStars;
|
|
/** write emitted output to disk*/
|
|
var writeEmittedFiles = writeJavaScriptFile;
|
|
var detachedCommentsInfo;
|
|
var writeComment = ts.writeCommentRange;
|
|
/** Emit a node */
|
|
var emit = emitNodeWithoutSourceMap;
|
|
/** Called just before starting emit of a node */
|
|
var emitStart = function (node) { };
|
|
/** Called once the emit of the node is done */
|
|
var emitEnd = function (node) { };
|
|
/** 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;
|
|
/** 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, scopeName) { };
|
|
/** Called after coming out of the scope */
|
|
var scopeEmitEnd = function () { };
|
|
/** Sourcemap data that will get encoded */
|
|
var sourceMapData;
|
|
if (compilerOptions.sourceMap) {
|
|
initializeEmitterWithSourceMaps();
|
|
}
|
|
if (root) {
|
|
// Do not call emit directly. It does not set the currentSourceFile.
|
|
emitSourceFile(root);
|
|
}
|
|
else {
|
|
ts.forEach(host.getSourceFiles(), function (sourceFile) {
|
|
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
|
|
emitSourceFile(sourceFile);
|
|
}
|
|
});
|
|
}
|
|
writeLine();
|
|
writeEmittedFiles(writer.getText(), compilerOptions.emitBOM);
|
|
return;
|
|
function emitSourceFile(sourceFile) {
|
|
currentSourceFile = sourceFile;
|
|
exportFunctionForFile = undefined;
|
|
emit(sourceFile);
|
|
}
|
|
function isUniqueName(name) {
|
|
return !resolver.hasGlobalName(name) &&
|
|
!ts.hasProperty(currentSourceFile.identifiers, name) &&
|
|
!ts.hasProperty(generatedNameSet, name);
|
|
}
|
|
// Return the next available name in the pattern _a ... _z, _0, _1, ...
|
|
// TempFlags._i or TempFlags._n may be used to express a preference for that dedicated name.
|
|
// Note that names generated by makeTempVariableName and makeUniqueName will never conflict.
|
|
function makeTempVariableName(flags) {
|
|
if (flags && !(tempFlags & flags)) {
|
|
var name = flags === 268435456 /* _i */ ? "_i" : "_n";
|
|
if (isUniqueName(name)) {
|
|
tempFlags |= flags;
|
|
return name;
|
|
}
|
|
}
|
|
while (true) {
|
|
var count = tempFlags & 268435455 /* CountMask */;
|
|
tempFlags++;
|
|
// Skip over 'i' and 'n'
|
|
if (count !== 8 && count !== 13) {
|
|
var name_1 = count < 26 ? "_" + String.fromCharCode(97 /* a */ + count) : "_" + (count - 26);
|
|
if (isUniqueName(name_1)) {
|
|
return name_1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Generate a name that is unique within the current file and doesn't conflict with any names
|
|
// in global scope. The name is formed by adding an '_n' suffix to the specified base name,
|
|
// where n is a positive integer. Note that names generated by makeTempVariableName and
|
|
// makeUniqueName are guaranteed to never conflict.
|
|
function makeUniqueName(baseName) {
|
|
// Find the first unique 'name_n', where n is a positive number
|
|
if (baseName.charCodeAt(baseName.length - 1) !== 95 /* _ */) {
|
|
baseName += "_";
|
|
}
|
|
var i = 1;
|
|
while (true) {
|
|
var generatedName = baseName + i;
|
|
if (isUniqueName(generatedName)) {
|
|
return generatedNameSet[generatedName] = generatedName;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
function assignGeneratedName(node, name) {
|
|
nodeToGeneratedName[ts.getNodeId(node)] = ts.unescapeIdentifier(name);
|
|
}
|
|
function generateNameForFunctionOrClassDeclaration(node) {
|
|
if (!node.name) {
|
|
assignGeneratedName(node, makeUniqueName("default"));
|
|
}
|
|
}
|
|
function generateNameForModuleOrEnum(node) {
|
|
if (node.name.kind === 65 /* Identifier */) {
|
|
var name_2 = node.name.text;
|
|
// Use module/enum name itself if it is unique, otherwise make a unique variation
|
|
assignGeneratedName(node, isUniqueLocalName(name_2, node) ? name_2 : makeUniqueName(name_2));
|
|
}
|
|
}
|
|
function generateNameForImportOrExportDeclaration(node) {
|
|
var expr = ts.getExternalModuleName(node);
|
|
var baseName = expr.kind === 8 /* StringLiteral */ ?
|
|
ts.escapeIdentifier(ts.makeIdentifierFromModuleName(expr.text)) : "module";
|
|
assignGeneratedName(node, makeUniqueName(baseName));
|
|
}
|
|
function generateNameForImportDeclaration(node) {
|
|
if (node.importClause) {
|
|
generateNameForImportOrExportDeclaration(node);
|
|
}
|
|
}
|
|
function generateNameForExportDeclaration(node) {
|
|
if (node.moduleSpecifier) {
|
|
generateNameForImportOrExportDeclaration(node);
|
|
}
|
|
}
|
|
function generateNameForExportAssignment(node) {
|
|
if (node.expression && node.expression.kind !== 65 /* Identifier */) {
|
|
assignGeneratedName(node, makeUniqueName("default"));
|
|
}
|
|
}
|
|
function generateNameForNode(node) {
|
|
switch (node.kind) {
|
|
case 200 /* FunctionDeclaration */:
|
|
case 201 /* ClassDeclaration */:
|
|
case 174 /* ClassExpression */:
|
|
generateNameForFunctionOrClassDeclaration(node);
|
|
break;
|
|
case 205 /* ModuleDeclaration */:
|
|
generateNameForModuleOrEnum(node);
|
|
generateNameForNode(node.body);
|
|
break;
|
|
case 204 /* EnumDeclaration */:
|
|
generateNameForModuleOrEnum(node);
|
|
break;
|
|
case 209 /* ImportDeclaration */:
|
|
generateNameForImportDeclaration(node);
|
|
break;
|
|
case 215 /* ExportDeclaration */:
|
|
generateNameForExportDeclaration(node);
|
|
break;
|
|
case 214 /* ExportAssignment */:
|
|
generateNameForExportAssignment(node);
|
|
break;
|
|
}
|
|
}
|
|
function getGeneratedNameForNode(node) {
|
|
var nodeId = ts.getNodeId(node);
|
|
if (!nodeToGeneratedName[nodeId]) {
|
|
generateNameForNode(node);
|
|
}
|
|
return nodeToGeneratedName[nodeId];
|
|
}
|
|
function initializeEmitterWithSourceMaps() {
|
|
var sourceMapDir; // The directory in which sourcemap will be
|
|
// Current source map file and its index in the sources list
|
|
var sourceMapSourceIndex = -1;
|
|
// Names and its index map
|
|
var sourceMapNameIndexMap = {};
|
|
var sourceMapNameIndices = [];
|
|
function getSourceMapNameIndex() {
|
|
return sourceMapNameIndices.length ? lastOrUndefined(sourceMapNameIndices) : -1;
|
|
}
|
|
// Last recorded and encoded spans
|
|
var lastRecordedSourceMapSpan;
|
|
var lastEncodedSourceMapSpan = {
|
|
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 delimiters
|
|
if (lastEncodedSourceMapSpan.emittedLine == lastRecordedSourceMapSpan.emittedLine) {
|
|
// Emit comma to separate the entry
|
|
if (sourceMapData.sourceMapMappings) {
|
|
sourceMapData.sourceMapMappings += ",";
|
|
}
|
|
}
|
|
else {
|
|
// Emit line delimiters
|
|
for (var encodedLine = lastEncodedSourceMapSpan.emittedLine; encodedLine < lastRecordedSourceMapSpan.emittedLine; encodedLine++) {
|
|
sourceMapData.sourceMapMappings += ";";
|
|
}
|
|
prevEncodedEmittedColumn = 1;
|
|
}
|
|
// 1. Relative Column 0 based
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.emittedColumn - prevEncodedEmittedColumn);
|
|
// 2. Relative sourceIndex
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceIndex - lastEncodedSourceMapSpan.sourceIndex);
|
|
// 3. Relative sourceLine 0 based
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceLine - lastEncodedSourceMapSpan.sourceLine);
|
|
// 4. Relative sourceColumn 0 based
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.sourceColumn - lastEncodedSourceMapSpan.sourceColumn);
|
|
// 5. Relative namePosition 0 based
|
|
if (lastRecordedSourceMapSpan.nameIndex >= 0) {
|
|
sourceMapData.sourceMapMappings += base64VLQFormatEncode(lastRecordedSourceMapSpan.nameIndex - lastEncodedNameIndex);
|
|
lastEncodedNameIndex = lastRecordedSourceMapSpan.nameIndex;
|
|
}
|
|
lastEncodedSourceMapSpan = lastRecordedSourceMapSpan;
|
|
sourceMapData.sourceMapDecodedMappings.push(lastEncodedSourceMapSpan);
|
|
function base64VLQFormatEncode(inValue) {
|
|
function base64FormatEncode(inValue) {
|
|
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;
|
|
}
|
|
}
|
|
function recordSourceMapSpan(pos) {
|
|
var sourceLinePos = ts.getLineAndCharacterOfPosition(currentSourceFile, pos);
|
|
// Convert the location to be one-based.
|
|
sourceLinePos.line++;
|
|
sourceLinePos.character++;
|
|
var emittedLine = writer.getLine();
|
|
var emittedColumn = writer.getColumn();
|
|
// If this location wasn't recorded or the location in source is going backwards, record the span
|
|
if (!lastRecordedSourceMapSpan ||
|
|
lastRecordedSourceMapSpan.emittedLine != emittedLine ||
|
|
lastRecordedSourceMapSpan.emittedColumn != emittedColumn ||
|
|
(lastRecordedSourceMapSpan.sourceIndex === sourceMapSourceIndex &&
|
|
(lastRecordedSourceMapSpan.sourceLine > sourceLinePos.line ||
|
|
(lastRecordedSourceMapSpan.sourceLine === sourceLinePos.line && lastRecordedSourceMapSpan.sourceColumn > sourceLinePos.character)))) {
|
|
// 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;
|
|
lastRecordedSourceMapSpan.sourceIndex = sourceMapSourceIndex;
|
|
}
|
|
}
|
|
function recordEmitNodeStartSpan(node) {
|
|
// Get the token pos after skipping to the token (ignoring the leading trivia)
|
|
recordSourceMapSpan(ts.skipTrivia(currentSourceFile.text, node.pos));
|
|
}
|
|
function recordEmitNodeEndSpan(node) {
|
|
recordSourceMapSpan(node.end);
|
|
}
|
|
function writeTextWithSpanRecord(tokenKind, startPos, emitFn) {
|
|
var tokenStartPos = ts.skipTrivia(currentSourceFile.text, startPos);
|
|
recordSourceMapSpan(tokenStartPos);
|
|
var tokenEndPos = emitTokenText(tokenKind, tokenStartPos, emitFn);
|
|
recordSourceMapSpan(tokenEndPos);
|
|
return tokenEndPos;
|
|
}
|
|
function recordNewSourceFileStart(node) {
|
|
// Add the file to tsFilePaths
|
|
// If sourceroot option: Use the relative path corresponding to the common directory path
|
|
// otherwise source locations relative to map file location
|
|
var sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir;
|
|
sourceMapData.sourceMapSources.push(ts.getRelativePathToDirectoryOrUrl(sourcesDirectoryPath, node.fileName, host.getCurrentDirectory(), host.getCanonicalFileName,
|
|
/*isAbsolutePathAnUrl*/ true));
|
|
sourceMapSourceIndex = sourceMapData.sourceMapSources.length - 1;
|
|
// The one that can be used from program to get the actual source file
|
|
sourceMapData.inputSourceFileNames.push(node.fileName);
|
|
}
|
|
function recordScopeNameOfNode(node, scopeName) {
|
|
function recordScopeNameIndex(scopeNameIndex) {
|
|
sourceMapNameIndices.push(scopeNameIndex);
|
|
}
|
|
function recordScopeNameStart(scopeName) {
|
|
var scopeNameIndex = -1;
|
|
if (scopeName) {
|
|
var parentIndex = getSourceMapNameIndex();
|
|
if (parentIndex !== -1) {
|
|
// Child scopes are always shown with a dot (even if they have no name),
|
|
// unless it is a computed property. Then it is shown with brackets,
|
|
// but the brackets are included in the name.
|
|
var name_3 = node.name;
|
|
if (!name_3 || name_3.kind !== 127 /* ComputedPropertyName */) {
|
|
scopeName = "." + scopeName;
|
|
}
|
|
scopeName = sourceMapData.sourceMapNames[parentIndex] + scopeName;
|
|
}
|
|
scopeNameIndex = ts.getProperty(sourceMapNameIndexMap, scopeName);
|
|
if (scopeNameIndex === undefined) {
|
|
scopeNameIndex = sourceMapData.sourceMapNames.length;
|
|
sourceMapData.sourceMapNames.push(scopeName);
|
|
sourceMapNameIndexMap[scopeName] = scopeNameIndex;
|
|
}
|
|
}
|
|
recordScopeNameIndex(scopeNameIndex);
|
|
}
|
|
if (scopeName) {
|
|
// The scope was already given a name use it
|
|
recordScopeNameStart(scopeName);
|
|
}
|
|
else if (node.kind === 200 /* FunctionDeclaration */ ||
|
|
node.kind === 162 /* FunctionExpression */ ||
|
|
node.kind === 134 /* MethodDeclaration */ ||
|
|
node.kind === 133 /* MethodSignature */ ||
|
|
node.kind === 136 /* GetAccessor */ ||
|
|
node.kind === 137 /* SetAccessor */ ||
|
|
node.kind === 205 /* ModuleDeclaration */ ||
|
|
node.kind === 201 /* ClassDeclaration */ ||
|
|
node.kind === 204 /* EnumDeclaration */) {
|
|
// Declaration and has associated name use it
|
|
if (node.name) {
|
|
var name_4 = node.name;
|
|
// For computed property names, the text will include the brackets
|
|
scopeName = name_4.kind === 127 /* ComputedPropertyName */
|
|
? ts.getTextOfNode(name_4)
|
|
: node.name.text;
|
|
}
|
|
recordScopeNameStart(scopeName);
|
|
}
|
|
else {
|
|
// Block just use the name from upper level scope
|
|
recordScopeNameIndex(getSourceMapNameIndex());
|
|
}
|
|
}
|
|
function recordScopeNameEnd() {
|
|
sourceMapNameIndices.pop();
|
|
}
|
|
;
|
|
function writeCommentRangeWithMap(curentSourceFile, writer, comment, newLine) {
|
|
recordSourceMapSpan(comment.pos);
|
|
ts.writeCommentRange(currentSourceFile, writer, comment, newLine);
|
|
recordSourceMapSpan(comment.end);
|
|
}
|
|
function serializeSourceMapContents(version, file, sourceRoot, sources, names, mappings) {
|
|
if (typeof JSON !== "undefined") {
|
|
return JSON.stringify({
|
|
version: version,
|
|
file: file,
|
|
sourceRoot: sourceRoot,
|
|
sources: sources,
|
|
names: names,
|
|
mappings: mappings
|
|
});
|
|
}
|
|
return "{\"version\":" + version + ",\"file\":\"" + ts.escapeString(file) + "\",\"sourceRoot\":\"" + ts.escapeString(sourceRoot) + "\",\"sources\":[" + serializeStringArray(sources) + "],\"names\":[" + serializeStringArray(names) + "],\"mappings\":\"" + ts.escapeString(mappings) + "\"}";
|
|
function serializeStringArray(list) {
|
|
var output = "";
|
|
for (var i = 0, n = list.length; i < n; i++) {
|
|
if (i) {
|
|
output += ",";
|
|
}
|
|
output += "\"" + ts.escapeString(list[i]) + "\"";
|
|
}
|
|
return output;
|
|
}
|
|
}
|
|
function writeJavaScriptAndSourceMapFile(emitOutput, writeByteOrderMark) {
|
|
// Write source map file
|
|
encodeLastRecordedSourceMapSpan();
|
|
ts.writeFile(host, diagnostics, sourceMapData.sourceMapFilePath, serializeSourceMapContents(3, sourceMapData.sourceMapFile, sourceMapData.sourceMapSourceRoot, sourceMapData.sourceMapSources, sourceMapData.sourceMapNames, sourceMapData.sourceMapMappings), false);
|
|
sourceMapDataList.push(sourceMapData);
|
|
// Write sourcemap url to the js file and write the js file
|
|
writeJavaScriptFile(emitOutput + "//# sourceMappingURL=" + sourceMapData.jsSourceMappingURL, writeByteOrderMark);
|
|
}
|
|
// Initialize source map data
|
|
var sourceMapJsFile = ts.getBaseFileName(ts.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) !== 47 /* slash */) {
|
|
sourceMapData.sourceMapSourceRoot += ts.directorySeparator;
|
|
}
|
|
if (compilerOptions.mapRoot) {
|
|
sourceMapDir = ts.normalizeSlashes(compilerOptions.mapRoot);
|
|
if (root) {
|
|
// 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 = ts.getDirectoryPath(ts.getSourceFilePathInNewDir(root, host, sourceMapDir));
|
|
}
|
|
if (!ts.isRootedDiskPath(sourceMapDir) && !ts.isUrl(sourceMapDir)) {
|
|
// The relative paths are relative to the common directory
|
|
sourceMapDir = ts.combinePaths(host.getCommonSourceDirectory(), sourceMapDir);
|
|
sourceMapData.jsSourceMappingURL = ts.getRelativePathToDirectoryOrUrl(ts.getDirectoryPath(ts.normalizePath(jsFilePath)), ts.combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL), host.getCurrentDirectory(), host.getCanonicalFileName,
|
|
/*isAbsolutePathAnUrl*/ true);
|
|
}
|
|
else {
|
|
sourceMapData.jsSourceMappingURL = ts.combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL);
|
|
}
|
|
}
|
|
else {
|
|
sourceMapDir = ts.getDirectoryPath(ts.normalizePath(jsFilePath));
|
|
}
|
|
function emitNodeWithSourceMap(node, allowGeneratedIdentifiers) {
|
|
if (node) {
|
|
if (ts.nodeIsSynthesized(node)) {
|
|
return emitNodeWithoutSourceMap(node, false);
|
|
}
|
|
if (node.kind != 227 /* SourceFile */) {
|
|
recordEmitNodeStartSpan(node);
|
|
emitNodeWithoutSourceMap(node, allowGeneratedIdentifiers);
|
|
recordEmitNodeEndSpan(node);
|
|
}
|
|
else {
|
|
recordNewSourceFileStart(node);
|
|
emitNodeWithoutSourceMap(node, false);
|
|
}
|
|
}
|
|
}
|
|
writeEmittedFiles = writeJavaScriptAndSourceMapFile;
|
|
emit = emitNodeWithSourceMap;
|
|
emitStart = recordEmitNodeStartSpan;
|
|
emitEnd = recordEmitNodeEndSpan;
|
|
emitToken = writeTextWithSpanRecord;
|
|
scopeEmitStart = recordScopeNameOfNode;
|
|
scopeEmitEnd = recordScopeNameEnd;
|
|
writeComment = writeCommentRangeWithMap;
|
|
}
|
|
function writeJavaScriptFile(emitOutput, writeByteOrderMark) {
|
|
ts.writeFile(host, diagnostics, jsFilePath, emitOutput, writeByteOrderMark);
|
|
}
|
|
// Create a temporary variable with a unique unused name.
|
|
function createTempVariable(flags) {
|
|
var result = ts.createSynthesizedNode(65 /* Identifier */);
|
|
result.text = makeTempVariableName(flags);
|
|
return result;
|
|
}
|
|
function recordTempDeclaration(name) {
|
|
if (!tempVariables) {
|
|
tempVariables = [];
|
|
}
|
|
tempVariables.push(name);
|
|
}
|
|
function createAndRecordTempVariable(flags) {
|
|
var temp = createTempVariable(flags);
|
|
recordTempDeclaration(temp);
|
|
return temp;
|
|
}
|
|
function emitTempDeclarations(newLine) {
|
|
if (tempVariables) {
|
|
if (newLine) {
|
|
writeLine();
|
|
}
|
|
else {
|
|
write(" ");
|
|
}
|
|
write("var ");
|
|
emitCommaList(tempVariables);
|
|
write(";");
|
|
}
|
|
}
|
|
function emitTokenText(tokenKind, startPos, emitFn) {
|
|
var tokenString = ts.tokenToString(tokenKind);
|
|
if (emitFn) {
|
|
emitFn();
|
|
}
|
|
else {
|
|
write(tokenString);
|
|
}
|
|
return startPos + tokenString.length;
|
|
}
|
|
function emitOptional(prefix, node) {
|
|
if (node) {
|
|
write(prefix);
|
|
emit(node);
|
|
}
|
|
}
|
|
function emitParenthesizedIf(node, parenthesized) {
|
|
if (parenthesized) {
|
|
write("(");
|
|
}
|
|
emit(node);
|
|
if (parenthesized) {
|
|
write(")");
|
|
}
|
|
}
|
|
function emitTrailingCommaIfPresent(nodeList) {
|
|
if (nodeList.hasTrailingComma) {
|
|
write(",");
|
|
}
|
|
}
|
|
function emitLinePreservingList(parent, nodes, allowTrailingComma, spacesBetweenBraces) {
|
|
ts.Debug.assert(nodes.length > 0);
|
|
increaseIndent();
|
|
if (nodeStartPositionsAreOnSameLine(parent, nodes[0])) {
|
|
if (spacesBetweenBraces) {
|
|
write(" ");
|
|
}
|
|
}
|
|
else {
|
|
writeLine();
|
|
}
|
|
for (var i = 0, n = nodes.length; i < n; i++) {
|
|
if (i) {
|
|
if (nodeEndIsOnSameLineAsNodeStart(nodes[i - 1], nodes[i])) {
|
|
write(", ");
|
|
}
|
|
else {
|
|
write(",");
|
|
writeLine();
|
|
}
|
|
}
|
|
emit(nodes[i]);
|
|
}
|
|
if (nodes.hasTrailingComma && allowTrailingComma) {
|
|
write(",");
|
|
}
|
|
decreaseIndent();
|
|
if (nodeEndPositionsAreOnSameLine(parent, ts.lastOrUndefined(nodes))) {
|
|
if (spacesBetweenBraces) {
|
|
write(" ");
|
|
}
|
|
}
|
|
else {
|
|
writeLine();
|
|
}
|
|
}
|
|
function emitList(nodes, start, count, multiLine, trailingComma, leadingComma, noTrailingNewLine, emitNode) {
|
|
if (!emitNode) {
|
|
emitNode = emit;
|
|
}
|
|
for (var i = 0; i < count; i++) {
|
|
if (multiLine) {
|
|
if (i || leadingComma) {
|
|
write(",");
|
|
}
|
|
writeLine();
|
|
}
|
|
else {
|
|
if (i || leadingComma) {
|
|
write(", ");
|
|
}
|
|
}
|
|
emitNode(nodes[start + i]);
|
|
leadingComma = true;
|
|
}
|
|
if (trailingComma) {
|
|
write(",");
|
|
}
|
|
if (multiLine && !noTrailingNewLine) {
|
|
writeLine();
|
|
}
|
|
return count;
|
|
}
|
|
function emitCommaList(nodes) {
|
|
if (nodes) {
|
|
emitList(nodes, 0, nodes.length, false, false);
|
|
}
|
|
}
|
|
function emitLines(nodes) {
|
|
emitLinesStartingAt(nodes, 0);
|
|
}
|
|
function emitLinesStartingAt(nodes, startIndex) {
|
|
for (var i = startIndex; i < nodes.length; i++) {
|
|
writeLine();
|
|
emit(nodes[i]);
|
|
}
|
|
}
|
|
function isBinaryOrOctalIntegerLiteral(node, text) {
|
|
if (node.kind === 7 /* NumericLiteral */ && text.length > 1) {
|
|
switch (text.charCodeAt(1)) {
|
|
case 98 /* b */:
|
|
case 66 /* B */:
|
|
case 111 /* o */:
|
|
case 79 /* O */:
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function emitLiteral(node) {
|
|
var text = getLiteralText(node);
|
|
if (compilerOptions.sourceMap && (node.kind === 8 /* StringLiteral */ || ts.isTemplateLiteralKind(node.kind))) {
|
|
writer.writeLiteral(text);
|
|
}
|
|
else if (languageVersion < 2 /* ES6 */ && isBinaryOrOctalIntegerLiteral(node, text)) {
|
|
write(node.text);
|
|
}
|
|
else {
|
|
write(text);
|
|
}
|
|
}
|
|
function getLiteralText(node) {
|
|
// Any template literal or string literal with an extended escape
|
|
// (e.g. "\u{0067}") will need to be downleveled as a escaped string literal.
|
|
if (languageVersion < 2 /* ES6 */ && (ts.isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) {
|
|
return getQuotedEscapedLiteralText('"', node.text, '"');
|
|
}
|
|
// If we don't need to downlevel and we can reach the original source text using
|
|
// the node's parent reference, then simply get the text as it was originally written.
|
|
if (node.parent) {
|
|
return ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, node);
|
|
}
|
|
// If we can't reach the original source text, use the canonical form if it's a number,
|
|
// or an escaped quoted form of the original text if it's string-like.
|
|
switch (node.kind) {
|
|
case 8 /* StringLiteral */:
|
|
return getQuotedEscapedLiteralText('"', node.text, '"');
|
|
case 10 /* NoSubstitutionTemplateLiteral */:
|
|
return getQuotedEscapedLiteralText('`', node.text, '`');
|
|
case 11 /* TemplateHead */:
|
|
return getQuotedEscapedLiteralText('`', node.text, '${');
|
|
case 12 /* TemplateMiddle */:
|
|
return getQuotedEscapedLiteralText('}', node.text, '${');
|
|
case 13 /* TemplateTail */:
|
|
return getQuotedEscapedLiteralText('}', node.text, '`');
|
|
case 7 /* NumericLiteral */:
|
|
return node.text;
|
|
}
|
|
ts.Debug.fail("Literal kind '" + node.kind + "' not accounted for.");
|
|
}
|
|
function getQuotedEscapedLiteralText(leftQuote, text, rightQuote) {
|
|
return leftQuote + ts.escapeNonAsciiCharacters(ts.escapeString(text)) + rightQuote;
|
|
}
|
|
function emitDownlevelRawTemplateLiteral(node) {
|
|
// Find original source text, since we need to emit the raw strings of the tagged template.
|
|
// The raw strings contain the (escaped) strings of what the user wrote.
|
|
// Examples: `\n` is converted to "\\n", a template string with a newline to "\n".
|
|
var text = ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, node);
|
|
// text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"),
|
|
// thus we need to remove those characters.
|
|
// First template piece starts with "`", others with "}"
|
|
// Last template piece ends with "`", others with "${"
|
|
var isLast = node.kind === 10 /* NoSubstitutionTemplateLiteral */ || node.kind === 13 /* TemplateTail */;
|
|
text = text.substring(1, text.length - (isLast ? 1 : 2));
|
|
// Newline normalization:
|
|
// ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's
|
|
// <CR><LF> and <CR> LineTerminatorSequences are normalized to <LF> for both TV and TRV.
|
|
text = text.replace(/\r\n?/g, "\n");
|
|
text = ts.escapeString(text);
|
|
write('"' + text + '"');
|
|
}
|
|
function emitDownlevelTaggedTemplateArray(node, literalEmitter) {
|
|
write("[");
|
|
if (node.template.kind === 10 /* NoSubstitutionTemplateLiteral */) {
|
|
literalEmitter(node.template);
|
|
}
|
|
else {
|
|
literalEmitter(node.template.head);
|
|
ts.forEach(node.template.templateSpans, function (child) {
|
|
write(", ");
|
|
literalEmitter(child.literal);
|
|
});
|
|
}
|
|
write("]");
|
|
}
|
|
function emitDownlevelTaggedTemplate(node) {
|
|
var tempVariable = createAndRecordTempVariable(0 /* Auto */);
|
|
write("(");
|
|
emit(tempVariable);
|
|
write(" = ");
|
|
emitDownlevelTaggedTemplateArray(node, emit);
|
|
write(", ");
|
|
emit(tempVariable);
|
|
write(".raw = ");
|
|
emitDownlevelTaggedTemplateArray(node, emitDownlevelRawTemplateLiteral);
|
|
write(", ");
|
|
emitParenthesizedIf(node.tag, needsParenthesisForPropertyAccessOrInvocation(node.tag));
|
|
write("(");
|
|
emit(tempVariable);
|
|
// Now we emit the expressions
|
|
if (node.template.kind === 171 /* TemplateExpression */) {
|
|
ts.forEach(node.template.templateSpans, function (templateSpan) {
|
|
write(", ");
|
|
var needsParens = templateSpan.expression.kind === 169 /* BinaryExpression */
|
|
&& templateSpan.expression.operatorToken.kind === 23 /* CommaToken */;
|
|
emitParenthesizedIf(templateSpan.expression, needsParens);
|
|
});
|
|
}
|
|
write("))");
|
|
}
|
|
function emitTemplateExpression(node) {
|
|
// In ES6 mode and above, we can simply emit each portion of a template in order, but in
|
|
// ES3 & ES5 we must convert the template expression into a series of string concatenations.
|
|
if (languageVersion >= 2 /* ES6 */) {
|
|
ts.forEachChild(node, emit);
|
|
return;
|
|
}
|
|
var emitOuterParens = ts.isExpression(node.parent)
|
|
&& templateNeedsParens(node, node.parent);
|
|
if (emitOuterParens) {
|
|
write("(");
|
|
}
|
|
var headEmitted = false;
|
|
if (shouldEmitTemplateHead()) {
|
|
emitLiteral(node.head);
|
|
headEmitted = true;
|
|
}
|
|
for (var i = 0, n = node.templateSpans.length; i < n; i++) {
|
|
var templateSpan = node.templateSpans[i];
|
|
// Check if the expression has operands and binds its operands less closely than binary '+'.
|
|
// If it does, we need to wrap the expression in parentheses. Otherwise, something like
|
|
// `abc${ 1 << 2 }`
|
|
// becomes
|
|
// "abc" + 1 << 2 + ""
|
|
// which is really
|
|
// ("abc" + 1) << (2 + "")
|
|
// rather than
|
|
// "abc" + (1 << 2) + ""
|
|
var needsParens = templateSpan.expression.kind !== 161 /* ParenthesizedExpression */
|
|
&& comparePrecedenceToBinaryPlus(templateSpan.expression) !== 1 /* GreaterThan */;
|
|
if (i > 0 || headEmitted) {
|
|
// If this is the first span and the head was not emitted, then this templateSpan's
|
|
// expression will be the first to be emitted. Don't emit the preceding ' + ' in that
|
|
// case.
|
|
write(" + ");
|
|
}
|
|
emitParenthesizedIf(templateSpan.expression, needsParens);
|
|
// Only emit if the literal is non-empty.
|
|
// The binary '+' operator is left-associative, so the first string concatenation
|
|
// with the head will force the result up to this point to be a string.
|
|
// Emitting a '+ ""' has no semantic effect for middles and tails.
|
|
if (templateSpan.literal.text.length !== 0) {
|
|
write(" + ");
|
|
emitLiteral(templateSpan.literal);
|
|
}
|
|
}
|
|
if (emitOuterParens) {
|
|
write(")");
|
|
}
|
|
function shouldEmitTemplateHead() {
|
|
// If this expression has an empty head literal and the first template span has a non-empty
|
|
// literal, then emitting the empty head literal is not necessary.
|
|
// `${ foo } and ${ bar }`
|
|
// can be emitted as
|
|
// foo + " and " + bar
|
|
// This is because it is only required that one of the first two operands in the emit
|
|
// output must be a string literal, so that the other operand and all following operands
|
|
// are forced into strings.
|
|
//
|
|
// If the first template span has an empty literal, then the head must still be emitted.
|
|
// `${ foo }${ bar }`
|
|
// must still be emitted as
|
|
// "" + foo + bar
|
|
// There is always atleast one templateSpan in this code path, since
|
|
// NoSubstitutionTemplateLiterals are directly emitted via emitLiteral()
|
|
ts.Debug.assert(node.templateSpans.length !== 0);
|
|
return node.head.text.length !== 0 || node.templateSpans[0].literal.text.length === 0;
|
|
}
|
|
function templateNeedsParens(template, parent) {
|
|
switch (parent.kind) {
|
|
case 157 /* CallExpression */:
|
|
case 158 /* NewExpression */:
|
|
return parent.expression === template;
|
|
case 159 /* TaggedTemplateExpression */:
|
|
case 161 /* ParenthesizedExpression */:
|
|
return false;
|
|
default:
|
|
return comparePrecedenceToBinaryPlus(parent) !== -1 /* LessThan */;
|
|
}
|
|
}
|
|
/**
|
|
* Returns whether the expression has lesser, greater,
|
|
* or equal precedence to the binary '+' operator
|
|
*/
|
|
function comparePrecedenceToBinaryPlus(expression) {
|
|
// All binary expressions have lower precedence than '+' apart from '*', '/', and '%'
|
|
// which have greater precedence and '-' which has equal precedence.
|
|
// All unary operators have a higher precedence apart from yield.
|
|
// Arrow functions and conditionals have a lower precedence,
|
|
// although we convert the former into regular function expressions in ES5 mode,
|
|
// and in ES6 mode this function won't get called anyway.
|
|
//
|
|
// TODO (drosen): Note that we need to account for the upcoming 'yield' and
|
|
// spread ('...') unary operators that are anticipated for ES6.
|
|
switch (expression.kind) {
|
|
case 169 /* BinaryExpression */:
|
|
switch (expression.operatorToken.kind) {
|
|
case 35 /* AsteriskToken */:
|
|
case 36 /* SlashToken */:
|
|
case 37 /* PercentToken */:
|
|
return 1 /* GreaterThan */;
|
|
case 33 /* PlusToken */:
|
|
case 34 /* MinusToken */:
|
|
return 0 /* EqualTo */;
|
|
default:
|
|
return -1 /* LessThan */;
|
|
}
|
|
case 172 /* YieldExpression */:
|
|
case 170 /* ConditionalExpression */:
|
|
return -1 /* LessThan */;
|
|
default:
|
|
return 1 /* GreaterThan */;
|
|
}
|
|
}
|
|
}
|
|
function emitTemplateSpan(span) {
|
|
emit(span.expression);
|
|
emit(span.literal);
|
|
}
|
|
// 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.
|
|
// For example, this is utilized when feeding in a result to Object.defineProperty.
|
|
function emitExpressionForPropertyName(node) {
|
|
ts.Debug.assert(node.kind !== 152 /* BindingElement */);
|
|
if (node.kind === 8 /* StringLiteral */) {
|
|
emitLiteral(node);
|
|
}
|
|
else if (node.kind === 127 /* ComputedPropertyName */) {
|
|
// if this is a decorated computed property, we will need to capture the result
|
|
// of the property expression so that we can apply decorators later. This is to ensure
|
|
// we don't introduce unintended side effects:
|
|
//
|
|
// class C {
|
|
// [_a = x]() { }
|
|
// }
|
|
//
|
|
// The emit for the decorated computed property decorator is:
|
|
//
|
|
// Object.defineProperty(C.prototype, _a, __decorate([dec], C.prototype, _a, Object.getOwnPropertyDescriptor(C.prototype, _a)));
|
|
//
|
|
if (ts.nodeIsDecorated(node.parent)) {
|
|
if (!computedPropertyNamesToGeneratedNames) {
|
|
computedPropertyNamesToGeneratedNames = [];
|
|
}
|
|
var generatedName = computedPropertyNamesToGeneratedNames[ts.getNodeId(node)];
|
|
if (generatedName) {
|
|
// we have already generated a variable for this node, write that value instead.
|
|
write(generatedName);
|
|
return;
|
|
}
|
|
generatedName = createAndRecordTempVariable(0 /* Auto */).text;
|
|
computedPropertyNamesToGeneratedNames[ts.getNodeId(node)] = generatedName;
|
|
write(generatedName);
|
|
write(" = ");
|
|
}
|
|
emit(node.expression);
|
|
}
|
|
else {
|
|
write("\"");
|
|
if (node.kind === 7 /* NumericLiteral */) {
|
|
write(node.text);
|
|
}
|
|
else {
|
|
writeTextOfNode(currentSourceFile, node);
|
|
}
|
|
write("\"");
|
|
}
|
|
}
|
|
function isNotExpressionIdentifier(node) {
|
|
var parent = node.parent;
|
|
switch (parent.kind) {
|
|
case 129 /* Parameter */:
|
|
case 198 /* VariableDeclaration */:
|
|
case 152 /* BindingElement */:
|
|
case 132 /* PropertyDeclaration */:
|
|
case 131 /* PropertySignature */:
|
|
case 224 /* PropertyAssignment */:
|
|
case 225 /* ShorthandPropertyAssignment */:
|
|
case 226 /* EnumMember */:
|
|
case 134 /* MethodDeclaration */:
|
|
case 133 /* MethodSignature */:
|
|
case 200 /* FunctionDeclaration */:
|
|
case 136 /* GetAccessor */:
|
|
case 137 /* SetAccessor */:
|
|
case 162 /* FunctionExpression */:
|
|
case 201 /* ClassDeclaration */:
|
|
case 202 /* InterfaceDeclaration */:
|
|
case 204 /* EnumDeclaration */:
|
|
case 205 /* ModuleDeclaration */:
|
|
case 208 /* ImportEqualsDeclaration */:
|
|
case 210 /* ImportClause */:
|
|
case 211 /* NamespaceImport */:
|
|
return parent.name === node;
|
|
case 213 /* ImportSpecifier */:
|
|
case 217 /* ExportSpecifier */:
|
|
return parent.name === node || parent.propertyName === node;
|
|
case 190 /* BreakStatement */:
|
|
case 189 /* ContinueStatement */:
|
|
case 214 /* ExportAssignment */:
|
|
return false;
|
|
case 194 /* LabeledStatement */:
|
|
return node.parent.label === node;
|
|
}
|
|
}
|
|
function emitExpressionIdentifier(node) {
|
|
var substitution = resolver.getExpressionNameSubstitution(node, getGeneratedNameForNode);
|
|
if (substitution) {
|
|
write(substitution);
|
|
}
|
|
else {
|
|
writeTextOfNode(currentSourceFile, node);
|
|
}
|
|
}
|
|
function getGeneratedNameForIdentifier(node) {
|
|
if (ts.nodeIsSynthesized(node) || !blockScopedVariableToGeneratedName) {
|
|
return undefined;
|
|
}
|
|
var variableId = resolver.getBlockScopedVariableId(node);
|
|
if (variableId === undefined) {
|
|
return undefined;
|
|
}
|
|
return blockScopedVariableToGeneratedName[variableId];
|
|
}
|
|
function emitIdentifier(node, allowGeneratedIdentifiers) {
|
|
if (allowGeneratedIdentifiers) {
|
|
var generatedName = getGeneratedNameForIdentifier(node);
|
|
if (generatedName) {
|
|
write(generatedName);
|
|
return;
|
|
}
|
|
}
|
|
if (!node.parent) {
|
|
write(node.text);
|
|
}
|
|
else if (!isNotExpressionIdentifier(node)) {
|
|
emitExpressionIdentifier(node);
|
|
}
|
|
else {
|
|
writeTextOfNode(currentSourceFile, node);
|
|
}
|
|
}
|
|
function emitThis(node) {
|
|
if (resolver.getNodeCheckFlags(node) & 2 /* LexicalThis */) {
|
|
write("_this");
|
|
}
|
|
else {
|
|
write("this");
|
|
}
|
|
}
|
|
function emitSuper(node) {
|
|
if (languageVersion >= 2 /* ES6 */) {
|
|
write("super");
|
|
}
|
|
else {
|
|
var flags = resolver.getNodeCheckFlags(node);
|
|
if (flags & 16 /* SuperInstance */) {
|
|
write("_super.prototype");
|
|
}
|
|
else {
|
|
write("_super");
|
|
}
|
|
}
|
|
}
|
|
function emitObjectBindingPattern(node) {
|
|
write("{ ");
|
|
var elements = node.elements;
|
|
emitList(elements, 0, elements.length, false, elements.hasTrailingComma);
|
|
write(" }");
|
|
}
|
|
function emitArrayBindingPattern(node) {
|
|
write("[");
|
|
var elements = node.elements;
|
|
emitList(elements, 0, elements.length, false, elements.hasTrailingComma);
|
|
write("]");
|
|
}
|
|
function emitBindingElement(node) {
|
|
if (node.propertyName) {
|
|
emit(node.propertyName, false);
|
|
write(": ");
|
|
}
|
|
if (node.dotDotDotToken) {
|
|
write("...");
|
|
}
|
|
if (ts.isBindingPattern(node.name)) {
|
|
emit(node.name);
|
|
}
|
|
else {
|
|
emitModuleMemberName(node);
|
|
}
|
|
emitOptional(" = ", node.initializer);
|
|
}
|
|
function emitSpreadElementExpression(node) {
|
|
write("...");
|
|
emit(node.expression);
|
|
}
|
|
function emitYieldExpression(node) {
|
|
write(ts.tokenToString(110 /* YieldKeyword */));
|
|
if (node.asteriskToken) {
|
|
write("*");
|
|
}
|
|
if (node.expression) {
|
|
write(" ");
|
|
emit(node.expression);
|
|
}
|
|
}
|
|
function needsParenthesisForPropertyAccessOrInvocation(node) {
|
|
switch (node.kind) {
|
|
case 65 /* Identifier */:
|
|
case 153 /* ArrayLiteralExpression */:
|
|
case 155 /* PropertyAccessExpression */:
|
|
case 156 /* ElementAccessExpression */:
|
|
case 157 /* CallExpression */:
|
|
case 161 /* ParenthesizedExpression */:
|
|
// This list is not exhaustive and only includes those cases that are relevant
|
|
// to the check in emitArrayLiteral. More cases can be added as needed.
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function emitListWithSpread(elements, multiLine, trailingComma) {
|
|
var pos = 0;
|
|
var group = 0;
|
|
var length = elements.length;
|
|
while (pos < length) {
|
|
// Emit using the pattern <group0>.concat(<group1>, <group2>, ...)
|
|
if (group === 1) {
|
|
write(".concat(");
|
|
}
|
|
else if (group > 1) {
|
|
write(", ");
|
|
}
|
|
var e = elements[pos];
|
|
if (e.kind === 173 /* SpreadElementExpression */) {
|
|
e = e.expression;
|
|
emitParenthesizedIf(e, group === 0 && needsParenthesisForPropertyAccessOrInvocation(e));
|
|
pos++;
|
|
}
|
|
else {
|
|
var i = pos;
|
|
while (i < length && elements[i].kind !== 173 /* SpreadElementExpression */) {
|
|
i++;
|
|
}
|
|
write("[");
|
|
if (multiLine) {
|
|
increaseIndent();
|
|
}
|
|
emitList(elements, pos, i - pos, multiLine, trailingComma && i === length);
|
|
if (multiLine) {
|
|
decreaseIndent();
|
|
}
|
|
write("]");
|
|
pos = i;
|
|
}
|
|
group++;
|
|
}
|
|
if (group > 1) {
|
|
write(")");
|
|
}
|
|
}
|
|
function isSpreadElementExpression(node) {
|
|
return node.kind === 173 /* SpreadElementExpression */;
|
|
}
|
|
function emitArrayLiteral(node) {
|
|
var elements = node.elements;
|
|
if (elements.length === 0) {
|
|
write("[]");
|
|
}
|
|
else if (languageVersion >= 2 /* ES6 */ || !ts.forEach(elements, isSpreadElementExpression)) {
|
|
write("[");
|
|
emitLinePreservingList(node, node.elements, elements.hasTrailingComma, false);
|
|
write("]");
|
|
}
|
|
else {
|
|
emitListWithSpread(elements, (node.flags & 512 /* MultiLine */) !== 0,
|
|
/*trailingComma*/ elements.hasTrailingComma);
|
|
}
|
|
}
|
|
function emitObjectLiteralBody(node, numElements) {
|
|
if (numElements === 0) {
|
|
write("{}");
|
|
return;
|
|
}
|
|
write("{");
|
|
if (numElements > 0) {
|
|
var properties = node.properties;
|
|
// If we are not doing a downlevel transformation for object literals,
|
|
// then try to preserve the original shape of the object literal.
|
|
// Otherwise just try to preserve the formatting.
|
|
if (numElements === properties.length) {
|
|
emitLinePreservingList(node, properties, languageVersion >= 1 /* ES5 */, true);
|
|
}
|
|
else {
|
|
var multiLine = (node.flags & 512 /* MultiLine */) !== 0;
|
|
if (!multiLine) {
|
|
write(" ");
|
|
}
|
|
else {
|
|
increaseIndent();
|
|
}
|
|
emitList(properties, 0, numElements, multiLine, false);
|
|
if (!multiLine) {
|
|
write(" ");
|
|
}
|
|
else {
|
|
decreaseIndent();
|
|
}
|
|
}
|
|
}
|
|
write("}");
|
|
}
|
|
function emitDownlevelObjectLiteralWithComputedProperties(node, firstComputedPropertyIndex) {
|
|
var multiLine = (node.flags & 512 /* MultiLine */) !== 0;
|
|
var properties = node.properties;
|
|
write("(");
|
|
if (multiLine) {
|
|
increaseIndent();
|
|
}
|
|
// For computed properties, we need to create a unique handle to the object
|
|
// literal so we can modify it without risking internal assignments tainting the object.
|
|
var tempVar = createAndRecordTempVariable(0 /* Auto */);
|
|
// Write out the first non-computed properties
|
|
// (or all properties if none of them are computed),
|
|
// then emit the rest through indexing on the temp variable.
|
|
emit(tempVar);
|
|
write(" = ");
|
|
emitObjectLiteralBody(node, firstComputedPropertyIndex);
|
|
for (var i = firstComputedPropertyIndex, n = properties.length; i < n; i++) {
|
|
writeComma();
|
|
var property = properties[i];
|
|
emitStart(property);
|
|
if (property.kind === 136 /* GetAccessor */ || property.kind === 137 /* SetAccessor */) {
|
|
// TODO (drosen): Reconcile with 'emitMemberFunctions'.
|
|
var accessors = ts.getAllAccessorDeclarations(node.properties, property);
|
|
if (property !== accessors.firstAccessor) {
|
|
continue;
|
|
}
|
|
write("Object.defineProperty(");
|
|
emit(tempVar);
|
|
write(", ");
|
|
emitStart(node.name);
|
|
emitExpressionForPropertyName(property.name);
|
|
emitEnd(property.name);
|
|
write(", {");
|
|
increaseIndent();
|
|
if (accessors.getAccessor) {
|
|
writeLine();
|
|
emitLeadingComments(accessors.getAccessor);
|
|
write("get: ");
|
|
emitStart(accessors.getAccessor);
|
|
write("function ");
|
|
emitSignatureAndBody(accessors.getAccessor);
|
|
emitEnd(accessors.getAccessor);
|
|
emitTrailingComments(accessors.getAccessor);
|
|
write(",");
|
|
}
|
|
if (accessors.setAccessor) {
|
|
writeLine();
|
|
emitLeadingComments(accessors.setAccessor);
|
|
write("set: ");
|
|
emitStart(accessors.setAccessor);
|
|
write("function ");
|
|
emitSignatureAndBody(accessors.setAccessor);
|
|
emitEnd(accessors.setAccessor);
|
|
emitTrailingComments(accessors.setAccessor);
|
|
write(",");
|
|
}
|
|
writeLine();
|
|
write("enumerable: true,");
|
|
writeLine();
|
|
write("configurable: true");
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("})");
|
|
emitEnd(property);
|
|
}
|
|
else {
|
|
emitLeadingComments(property);
|
|
emitStart(property.name);
|
|
emit(tempVar);
|
|
emitMemberAccessForPropertyName(property.name);
|
|
emitEnd(property.name);
|
|
write(" = ");
|
|
if (property.kind === 224 /* PropertyAssignment */) {
|
|
emit(property.initializer);
|
|
}
|
|
else if (property.kind === 225 /* ShorthandPropertyAssignment */) {
|
|
emitExpressionIdentifier(property.name);
|
|
}
|
|
else if (property.kind === 134 /* MethodDeclaration */) {
|
|
emitFunctionDeclaration(property);
|
|
}
|
|
else {
|
|
ts.Debug.fail("ObjectLiteralElement type not accounted for: " + property.kind);
|
|
}
|
|
}
|
|
emitEnd(property);
|
|
}
|
|
writeComma();
|
|
emit(tempVar);
|
|
if (multiLine) {
|
|
decreaseIndent();
|
|
writeLine();
|
|
}
|
|
write(")");
|
|
function writeComma() {
|
|
if (multiLine) {
|
|
write(",");
|
|
writeLine();
|
|
}
|
|
else {
|
|
write(", ");
|
|
}
|
|
}
|
|
}
|
|
function emitObjectLiteral(node) {
|
|
var properties = node.properties;
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
var numProperties = properties.length;
|
|
// Find the first computed property.
|
|
// Everything until that point can be emitted as part of the initial object literal.
|
|
var numInitialNonComputedProperties = numProperties;
|
|
for (var i = 0, n = properties.length; i < n; i++) {
|
|
if (properties[i].name.kind === 127 /* ComputedPropertyName */) {
|
|
numInitialNonComputedProperties = i;
|
|
break;
|
|
}
|
|
}
|
|
var hasComputedProperty = numInitialNonComputedProperties !== properties.length;
|
|
if (hasComputedProperty) {
|
|
emitDownlevelObjectLiteralWithComputedProperties(node, numInitialNonComputedProperties);
|
|
return;
|
|
}
|
|
}
|
|
// Ordinary case: either the object has no computed properties
|
|
// or we're compiling with an ES6+ target.
|
|
emitObjectLiteralBody(node, properties.length);
|
|
}
|
|
function createBinaryExpression(left, operator, right, startsOnNewLine) {
|
|
var result = ts.createSynthesizedNode(169 /* BinaryExpression */, startsOnNewLine);
|
|
result.operatorToken = ts.createSynthesizedNode(operator);
|
|
result.left = left;
|
|
result.right = right;
|
|
return result;
|
|
}
|
|
function createPropertyAccessExpression(expression, name) {
|
|
var result = ts.createSynthesizedNode(155 /* PropertyAccessExpression */);
|
|
result.expression = parenthesizeForAccess(expression);
|
|
result.dotToken = ts.createSynthesizedNode(20 /* DotToken */);
|
|
result.name = name;
|
|
return result;
|
|
}
|
|
function createElementAccessExpression(expression, argumentExpression) {
|
|
var result = ts.createSynthesizedNode(156 /* ElementAccessExpression */);
|
|
result.expression = parenthesizeForAccess(expression);
|
|
result.argumentExpression = argumentExpression;
|
|
return result;
|
|
}
|
|
function parenthesizeForAccess(expr) {
|
|
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
|
|
// to parenthesize the expression before a dot. The known exceptions are:
|
|
//
|
|
// NewExpression:
|
|
// new C.x -> not the same as (new C).x
|
|
// NumberLiteral
|
|
// 1.x -> not the same as (1).x
|
|
//
|
|
if (ts.isLeftHandSideExpression(expr) && expr.kind !== 158 /* NewExpression */ && expr.kind !== 7 /* NumericLiteral */) {
|
|
return expr;
|
|
}
|
|
var node = ts.createSynthesizedNode(161 /* ParenthesizedExpression */);
|
|
node.expression = expr;
|
|
return node;
|
|
}
|
|
function emitComputedPropertyName(node) {
|
|
write("[");
|
|
emitExpressionForPropertyName(node);
|
|
write("]");
|
|
}
|
|
function emitMethod(node) {
|
|
if (languageVersion >= 2 /* ES6 */ && node.asteriskToken) {
|
|
write("*");
|
|
}
|
|
emit(node.name, false);
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
write(": function ");
|
|
}
|
|
emitSignatureAndBody(node);
|
|
}
|
|
function emitPropertyAssignment(node) {
|
|
emit(node.name, false);
|
|
write(": ");
|
|
emit(node.initializer);
|
|
}
|
|
function emitShorthandPropertyAssignment(node) {
|
|
emit(node.name, false);
|
|
// If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example:
|
|
// module m {
|
|
// export let y;
|
|
// }
|
|
// module m {
|
|
// export let obj = { y };
|
|
// }
|
|
// The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
// Emit identifier as an identifier
|
|
write(": ");
|
|
var generatedName = getGeneratedNameForIdentifier(node.name);
|
|
if (generatedName) {
|
|
write(generatedName);
|
|
}
|
|
else {
|
|
// Even though this is stored as identifier treat it as an expression
|
|
// Short-hand, { x }, is equivalent of normal form { x: x }
|
|
emitExpressionIdentifier(node.name);
|
|
}
|
|
}
|
|
else if (resolver.getExpressionNameSubstitution(node.name, getGeneratedNameForNode)) {
|
|
// Emit identifier as an identifier
|
|
write(": ");
|
|
// Even though this is stored as identifier treat it as an expression
|
|
// Short-hand, { x }, is equivalent of normal form { x: x }
|
|
emitExpressionIdentifier(node.name);
|
|
}
|
|
}
|
|
function tryEmitConstantValue(node) {
|
|
if (compilerOptions.separateCompilation) {
|
|
// do not inline enum values in separate compilation mode
|
|
return false;
|
|
}
|
|
var constantValue = resolver.getConstantValue(node);
|
|
if (constantValue !== undefined) {
|
|
write(constantValue.toString());
|
|
if (!compilerOptions.removeComments) {
|
|
var propertyName = node.kind === 155 /* PropertyAccessExpression */ ? ts.declarationNameToString(node.name) : ts.getTextOfNode(node.argumentExpression);
|
|
write(" /* " + propertyName + " */");
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
// Returns 'true' if the code was actually indented, false otherwise.
|
|
// If the code is not indented, an optional valueToWriteWhenNotIndenting will be
|
|
// emitted instead.
|
|
function indentIfOnDifferentLines(parent, node1, node2, valueToWriteWhenNotIndenting) {
|
|
var realNodesAreOnDifferentLines = !ts.nodeIsSynthesized(parent) && !nodeEndIsOnSameLineAsNodeStart(node1, node2);
|
|
// Always use a newline for synthesized code if the synthesizer desires it.
|
|
var synthesizedNodeIsOnDifferentLine = synthesizedNodeStartsOnNewLine(node2);
|
|
if (realNodesAreOnDifferentLines || synthesizedNodeIsOnDifferentLine) {
|
|
increaseIndent();
|
|
writeLine();
|
|
return true;
|
|
}
|
|
else {
|
|
if (valueToWriteWhenNotIndenting) {
|
|
write(valueToWriteWhenNotIndenting);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
function emitPropertyAccess(node) {
|
|
if (tryEmitConstantValue(node)) {
|
|
return;
|
|
}
|
|
emit(node.expression);
|
|
var indentedBeforeDot = indentIfOnDifferentLines(node, node.expression, node.dotToken);
|
|
write(".");
|
|
var indentedAfterDot = indentIfOnDifferentLines(node, node.dotToken, node.name);
|
|
emit(node.name, false);
|
|
decreaseIndentIf(indentedBeforeDot, indentedAfterDot);
|
|
}
|
|
function emitQualifiedName(node) {
|
|
emit(node.left);
|
|
write(".");
|
|
emit(node.right);
|
|
}
|
|
function emitIndexedAccess(node) {
|
|
if (tryEmitConstantValue(node)) {
|
|
return;
|
|
}
|
|
emit(node.expression);
|
|
write("[");
|
|
emit(node.argumentExpression);
|
|
write("]");
|
|
}
|
|
function hasSpreadElement(elements) {
|
|
return ts.forEach(elements, function (e) { return e.kind === 173 /* SpreadElementExpression */; });
|
|
}
|
|
function skipParentheses(node) {
|
|
while (node.kind === 161 /* ParenthesizedExpression */ || node.kind === 160 /* TypeAssertionExpression */) {
|
|
node = node.expression;
|
|
}
|
|
return node;
|
|
}
|
|
function emitCallTarget(node) {
|
|
if (node.kind === 65 /* Identifier */ || node.kind === 93 /* ThisKeyword */ || node.kind === 91 /* SuperKeyword */) {
|
|
emit(node);
|
|
return node;
|
|
}
|
|
var temp = createAndRecordTempVariable(0 /* Auto */);
|
|
write("(");
|
|
emit(temp);
|
|
write(" = ");
|
|
emit(node);
|
|
write(")");
|
|
return temp;
|
|
}
|
|
function emitCallWithSpread(node) {
|
|
var target;
|
|
var expr = skipParentheses(node.expression);
|
|
if (expr.kind === 155 /* PropertyAccessExpression */) {
|
|
// Target will be emitted as "this" argument
|
|
target = emitCallTarget(expr.expression);
|
|
write(".");
|
|
emit(expr.name);
|
|
}
|
|
else if (expr.kind === 156 /* ElementAccessExpression */) {
|
|
// Target will be emitted as "this" argument
|
|
target = emitCallTarget(expr.expression);
|
|
write("[");
|
|
emit(expr.argumentExpression);
|
|
write("]");
|
|
}
|
|
else if (expr.kind === 91 /* SuperKeyword */) {
|
|
target = expr;
|
|
write("_super");
|
|
}
|
|
else {
|
|
emit(node.expression);
|
|
}
|
|
write(".apply(");
|
|
if (target) {
|
|
if (target.kind === 91 /* SuperKeyword */) {
|
|
// Calls of form super(...) and super.foo(...)
|
|
emitThis(target);
|
|
}
|
|
else {
|
|
// Calls of form obj.foo(...)
|
|
emit(target);
|
|
}
|
|
}
|
|
else {
|
|
// Calls of form foo(...)
|
|
write("void 0");
|
|
}
|
|
write(", ");
|
|
emitListWithSpread(node.arguments, false, false);
|
|
write(")");
|
|
}
|
|
function emitCallExpression(node) {
|
|
if (languageVersion < 2 /* ES6 */ && hasSpreadElement(node.arguments)) {
|
|
emitCallWithSpread(node);
|
|
return;
|
|
}
|
|
var superCall = false;
|
|
if (node.expression.kind === 91 /* SuperKeyword */) {
|
|
emitSuper(node.expression);
|
|
superCall = true;
|
|
}
|
|
else {
|
|
emit(node.expression);
|
|
superCall = node.expression.kind === 155 /* PropertyAccessExpression */ && node.expression.expression.kind === 91 /* SuperKeyword */;
|
|
}
|
|
if (superCall && languageVersion < 2 /* ES6 */) {
|
|
write(".call(");
|
|
emitThis(node.expression);
|
|
if (node.arguments.length) {
|
|
write(", ");
|
|
emitCommaList(node.arguments);
|
|
}
|
|
write(")");
|
|
}
|
|
else {
|
|
write("(");
|
|
emitCommaList(node.arguments);
|
|
write(")");
|
|
}
|
|
}
|
|
function emitNewExpression(node) {
|
|
write("new ");
|
|
emit(node.expression);
|
|
if (node.arguments) {
|
|
write("(");
|
|
emitCommaList(node.arguments);
|
|
write(")");
|
|
}
|
|
}
|
|
function emitTaggedTemplateExpression(node) {
|
|
if (languageVersion >= 2 /* ES6 */) {
|
|
emit(node.tag);
|
|
write(" ");
|
|
emit(node.template);
|
|
}
|
|
else {
|
|
emitDownlevelTaggedTemplate(node);
|
|
}
|
|
}
|
|
function emitParenExpression(node) {
|
|
if (!node.parent || node.parent.kind !== 163 /* ArrowFunction */) {
|
|
if (node.expression.kind === 160 /* TypeAssertionExpression */) {
|
|
var operand = node.expression.expression;
|
|
// Make sure we consider all nested cast expressions, e.g.:
|
|
// (<any><number><any>-A).x;
|
|
while (operand.kind == 160 /* TypeAssertionExpression */) {
|
|
operand = operand.expression;
|
|
}
|
|
// 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 !== 167 /* PrefixUnaryExpression */ &&
|
|
operand.kind !== 166 /* VoidExpression */ &&
|
|
operand.kind !== 165 /* TypeOfExpression */ &&
|
|
operand.kind !== 164 /* DeleteExpression */ &&
|
|
operand.kind !== 168 /* PostfixUnaryExpression */ &&
|
|
operand.kind !== 158 /* NewExpression */ &&
|
|
!(operand.kind === 157 /* CallExpression */ && node.parent.kind === 158 /* NewExpression */) &&
|
|
!(operand.kind === 162 /* FunctionExpression */ && node.parent.kind === 157 /* CallExpression */)) {
|
|
emit(operand);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
write("(");
|
|
emit(node.expression);
|
|
write(")");
|
|
}
|
|
function emitDeleteExpression(node) {
|
|
write(ts.tokenToString(74 /* DeleteKeyword */));
|
|
write(" ");
|
|
emit(node.expression);
|
|
}
|
|
function emitVoidExpression(node) {
|
|
write(ts.tokenToString(99 /* VoidKeyword */));
|
|
write(" ");
|
|
emit(node.expression);
|
|
}
|
|
function emitTypeOfExpression(node) {
|
|
write(ts.tokenToString(97 /* TypeOfKeyword */));
|
|
write(" ");
|
|
emit(node.expression);
|
|
}
|
|
function isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node) {
|
|
if (!isCurrentFileSystemExternalModule() || node.kind !== 65 /* Identifier */ || ts.nodeIsSynthesized(node)) {
|
|
return false;
|
|
}
|
|
var isVariableDeclarationOrBindingElement = node.parent && (node.parent.kind === 198 /* VariableDeclaration */ || node.parent.kind === 152 /* BindingElement */);
|
|
var targetDeclaration = isVariableDeclarationOrBindingElement
|
|
? node.parent
|
|
: resolver.getReferencedValueDeclaration(node);
|
|
return isSourceFileLevelDeclarationInSystemExternalModule(targetDeclaration, true);
|
|
}
|
|
function emitPrefixUnaryExpression(node) {
|
|
var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
|
|
if (exportChanged) {
|
|
// emit
|
|
// ++x
|
|
// as
|
|
// exports('x', ++x)
|
|
write(exportFunctionForFile + "(\"");
|
|
emitNodeWithoutSourceMap(node.operand);
|
|
write("\", ");
|
|
}
|
|
write(ts.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 identifier, like delete or typeof. We also need to do this for plus
|
|
// and minus expressions in certain cases. Specifically, consider the following two cases (parens
|
|
// are just for clarity of exposition, and not part of the source code):
|
|
//
|
|
// (+(+1))
|
|
// (+(++1))
|
|
//
|
|
// We need to emit a space in both cases. In the first case, the absence of a space will make
|
|
// the resulting expression a prefix increment operation. And in the second, it will make the resulting
|
|
// expression a prefix increment whose operand is a plus expression - (++(+x))
|
|
// The same is true of minus of course.
|
|
if (node.operand.kind === 167 /* PrefixUnaryExpression */) {
|
|
var operand = node.operand;
|
|
if (node.operator === 33 /* PlusToken */ && (operand.operator === 33 /* PlusToken */ || operand.operator === 38 /* PlusPlusToken */)) {
|
|
write(" ");
|
|
}
|
|
else if (node.operator === 34 /* MinusToken */ && (operand.operator === 34 /* MinusToken */ || operand.operator === 39 /* MinusMinusToken */)) {
|
|
write(" ");
|
|
}
|
|
}
|
|
emit(node.operand);
|
|
if (exportChanged) {
|
|
write(")");
|
|
}
|
|
}
|
|
function emitPostfixUnaryExpression(node) {
|
|
var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
|
|
if (exportChanged) {
|
|
// export function returns the value that was passes as the second argument
|
|
// however for postfix unary expressions result value should be the value before modification.
|
|
// emit 'x++' as '(export('x', ++x) - 1)' and 'x--' as '(export('x', --x) + 1)'
|
|
write("(" + exportFunctionForFile + "(\"");
|
|
emitNodeWithoutSourceMap(node.operand);
|
|
write("\", ");
|
|
write(ts.tokenToString(node.operator));
|
|
emit(node.operand);
|
|
if (node.operator === 38 /* PlusPlusToken */) {
|
|
write(") - 1)");
|
|
}
|
|
else {
|
|
write(") + 1)");
|
|
}
|
|
}
|
|
else {
|
|
emit(node.operand);
|
|
write(ts.tokenToString(node.operator));
|
|
}
|
|
}
|
|
/*
|
|
* Checks if given node is a source file level declaration (not nested in module/function).
|
|
* If 'isExported' is true - then declaration must also be exported.
|
|
* This function is used in two cases:
|
|
* - check if node is a exported source file level value to determine
|
|
* if we should also export the value after its it changed
|
|
* - check if node is a source level declaration to emit it differently,
|
|
* i.e non-exported variable statement 'var x = 1' is hoisted so
|
|
* we we emit variable statement 'var' should be dropped.
|
|
*/
|
|
function isSourceFileLevelDeclarationInSystemExternalModule(node, isExported) {
|
|
if (!node || languageVersion >= 2 /* ES6 */ || !isCurrentFileSystemExternalModule()) {
|
|
return false;
|
|
}
|
|
var current = node;
|
|
while (current) {
|
|
if (current.kind === 227 /* SourceFile */) {
|
|
return !isExported || ((ts.getCombinedNodeFlags(node) & 1 /* Export */) !== 0);
|
|
}
|
|
else if (ts.isFunctionLike(current) || current.kind === 206 /* ModuleBlock */) {
|
|
return false;
|
|
}
|
|
else {
|
|
current = current.parent;
|
|
}
|
|
}
|
|
}
|
|
function emitBinaryExpression(node) {
|
|
if (languageVersion < 2 /* ES6 */ && node.operatorToken.kind === 53 /* EqualsToken */ &&
|
|
(node.left.kind === 154 /* ObjectLiteralExpression */ || node.left.kind === 153 /* ArrayLiteralExpression */)) {
|
|
emitDestructuring(node, node.parent.kind === 182 /* ExpressionStatement */);
|
|
}
|
|
else {
|
|
var exportChanged = node.operatorToken.kind >= 53 /* FirstAssignment */ &&
|
|
node.operatorToken.kind <= 64 /* LastAssignment */ &&
|
|
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left);
|
|
if (exportChanged) {
|
|
// emit assignment 'x <op> y' as 'exports("x", x <op> y)'
|
|
write(exportFunctionForFile + "(\"");
|
|
emitNodeWithoutSourceMap(node.left);
|
|
write("\", ");
|
|
}
|
|
emit(node.left);
|
|
var indentedBeforeOperator = indentIfOnDifferentLines(node, node.left, node.operatorToken, node.operatorToken.kind !== 23 /* CommaToken */ ? " " : undefined);
|
|
write(ts.tokenToString(node.operatorToken.kind));
|
|
var indentedAfterOperator = indentIfOnDifferentLines(node, node.operatorToken, node.right, " ");
|
|
emit(node.right);
|
|
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
|
|
if (exportChanged) {
|
|
write(")");
|
|
}
|
|
}
|
|
}
|
|
function synthesizedNodeStartsOnNewLine(node) {
|
|
return ts.nodeIsSynthesized(node) && node.startsOnNewLine;
|
|
}
|
|
function emitConditionalExpression(node) {
|
|
emit(node.condition);
|
|
var indentedBeforeQuestion = indentIfOnDifferentLines(node, node.condition, node.questionToken, " ");
|
|
write("?");
|
|
var indentedAfterQuestion = indentIfOnDifferentLines(node, node.questionToken, node.whenTrue, " ");
|
|
emit(node.whenTrue);
|
|
decreaseIndentIf(indentedBeforeQuestion, indentedAfterQuestion);
|
|
var indentedBeforeColon = indentIfOnDifferentLines(node, node.whenTrue, node.colonToken, " ");
|
|
write(":");
|
|
var indentedAfterColon = indentIfOnDifferentLines(node, node.colonToken, node.whenFalse, " ");
|
|
emit(node.whenFalse);
|
|
decreaseIndentIf(indentedBeforeColon, indentedAfterColon);
|
|
}
|
|
// Helper function to decrease the indent if we previously indented. Allows multiple
|
|
// previous indent values to be considered at a time. This also allows caller to just
|
|
// call this once, passing in all their appropriate indent values, instead of needing
|
|
// to call this helper function multiple times.
|
|
function decreaseIndentIf(value1, value2) {
|
|
if (value1) {
|
|
decreaseIndent();
|
|
}
|
|
if (value2) {
|
|
decreaseIndent();
|
|
}
|
|
}
|
|
function isSingleLineEmptyBlock(node) {
|
|
if (node && node.kind === 179 /* Block */) {
|
|
var block = node;
|
|
return block.statements.length === 0 && nodeEndIsOnSameLineAsNodeStart(block, block);
|
|
}
|
|
}
|
|
function emitBlock(node) {
|
|
if (isSingleLineEmptyBlock(node)) {
|
|
emitToken(14 /* OpenBraceToken */, node.pos);
|
|
write(" ");
|
|
emitToken(15 /* CloseBraceToken */, node.statements.end);
|
|
return;
|
|
}
|
|
emitToken(14 /* OpenBraceToken */, node.pos);
|
|
increaseIndent();
|
|
scopeEmitStart(node.parent);
|
|
if (node.kind === 206 /* ModuleBlock */) {
|
|
ts.Debug.assert(node.parent.kind === 205 /* ModuleDeclaration */);
|
|
emitCaptureThisForNodeIfNecessary(node.parent);
|
|
}
|
|
emitLines(node.statements);
|
|
if (node.kind === 206 /* ModuleBlock */) {
|
|
emitTempDeclarations(true);
|
|
}
|
|
decreaseIndent();
|
|
writeLine();
|
|
emitToken(15 /* CloseBraceToken */, node.statements.end);
|
|
scopeEmitEnd();
|
|
}
|
|
function emitEmbeddedStatement(node) {
|
|
if (node.kind === 179 /* Block */) {
|
|
write(" ");
|
|
emit(node);
|
|
}
|
|
else {
|
|
increaseIndent();
|
|
writeLine();
|
|
emit(node);
|
|
decreaseIndent();
|
|
}
|
|
}
|
|
function emitExpressionStatement(node) {
|
|
emitParenthesizedIf(node.expression, node.expression.kind === 163 /* ArrowFunction */);
|
|
write(";");
|
|
}
|
|
function emitIfStatement(node) {
|
|
var endPos = emitToken(84 /* IfKeyword */, node.pos);
|
|
write(" ");
|
|
endPos = emitToken(16 /* OpenParenToken */, endPos);
|
|
emit(node.expression);
|
|
emitToken(17 /* CloseParenToken */, node.expression.end);
|
|
emitEmbeddedStatement(node.thenStatement);
|
|
if (node.elseStatement) {
|
|
writeLine();
|
|
emitToken(76 /* ElseKeyword */, node.thenStatement.end);
|
|
if (node.elseStatement.kind === 183 /* IfStatement */) {
|
|
write(" ");
|
|
emit(node.elseStatement);
|
|
}
|
|
else {
|
|
emitEmbeddedStatement(node.elseStatement);
|
|
}
|
|
}
|
|
}
|
|
function emitDoStatement(node) {
|
|
write("do");
|
|
emitEmbeddedStatement(node.statement);
|
|
if (node.statement.kind === 179 /* Block */) {
|
|
write(" ");
|
|
}
|
|
else {
|
|
writeLine();
|
|
}
|
|
write("while (");
|
|
emit(node.expression);
|
|
write(");");
|
|
}
|
|
function emitWhileStatement(node) {
|
|
write("while (");
|
|
emit(node.expression);
|
|
write(")");
|
|
emitEmbeddedStatement(node.statement);
|
|
}
|
|
/* Returns true if start of variable declaration list was emitted.
|
|
* Return false if nothing was written - this can happen for source file level variable declarations
|
|
* in system modules - such variable declarations are hoisted.
|
|
*/
|
|
function tryEmitStartOfVariableDeclarationList(decl, startPos) {
|
|
if (shouldHoistVariable(decl, true)) {
|
|
// variables in variable declaration list were already hoisted
|
|
return false;
|
|
}
|
|
var tokenKind = 98 /* VarKeyword */;
|
|
if (decl && languageVersion >= 2 /* ES6 */) {
|
|
if (ts.isLet(decl)) {
|
|
tokenKind = 104 /* LetKeyword */;
|
|
}
|
|
else if (ts.isConst(decl)) {
|
|
tokenKind = 70 /* ConstKeyword */;
|
|
}
|
|
}
|
|
if (startPos !== undefined) {
|
|
emitToken(tokenKind, startPos);
|
|
write(" ");
|
|
}
|
|
else {
|
|
switch (tokenKind) {
|
|
case 98 /* VarKeyword */:
|
|
write("var ");
|
|
break;
|
|
case 104 /* LetKeyword */:
|
|
write("let ");
|
|
break;
|
|
case 70 /* ConstKeyword */:
|
|
write("const ");
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function emitVariableDeclarationListSkippingUninitializedEntries(list) {
|
|
var started = false;
|
|
for (var _i = 0, _a = list.declarations; _i < _a.length; _i++) {
|
|
var decl = _a[_i];
|
|
if (!decl.initializer) {
|
|
continue;
|
|
}
|
|
if (!started) {
|
|
started = true;
|
|
}
|
|
else {
|
|
write(", ");
|
|
}
|
|
emit(decl);
|
|
}
|
|
return started;
|
|
}
|
|
function emitForStatement(node) {
|
|
var endPos = emitToken(82 /* ForKeyword */, node.pos);
|
|
write(" ");
|
|
endPos = emitToken(16 /* OpenParenToken */, endPos);
|
|
if (node.initializer && node.initializer.kind === 199 /* VariableDeclarationList */) {
|
|
var variableDeclarationList = node.initializer;
|
|
var startIsEmitted = tryEmitStartOfVariableDeclarationList(variableDeclarationList, endPos);
|
|
if (startIsEmitted) {
|
|
emitCommaList(variableDeclarationList.declarations);
|
|
}
|
|
else {
|
|
emitVariableDeclarationListSkippingUninitializedEntries(variableDeclarationList);
|
|
}
|
|
}
|
|
else if (node.initializer) {
|
|
emit(node.initializer);
|
|
}
|
|
write(";");
|
|
emitOptional(" ", node.condition);
|
|
write(";");
|
|
emitOptional(" ", node.iterator);
|
|
write(")");
|
|
emitEmbeddedStatement(node.statement);
|
|
}
|
|
function emitForInOrForOfStatement(node) {
|
|
if (languageVersion < 2 /* ES6 */ && node.kind === 188 /* ForOfStatement */) {
|
|
return emitDownLevelForOfStatement(node);
|
|
}
|
|
var endPos = emitToken(82 /* ForKeyword */, node.pos);
|
|
write(" ");
|
|
endPos = emitToken(16 /* OpenParenToken */, endPos);
|
|
if (node.initializer.kind === 199 /* VariableDeclarationList */) {
|
|
var variableDeclarationList = node.initializer;
|
|
if (variableDeclarationList.declarations.length >= 1) {
|
|
tryEmitStartOfVariableDeclarationList(variableDeclarationList, endPos);
|
|
emit(variableDeclarationList.declarations[0]);
|
|
}
|
|
}
|
|
else {
|
|
emit(node.initializer);
|
|
}
|
|
if (node.kind === 187 /* ForInStatement */) {
|
|
write(" in ");
|
|
}
|
|
else {
|
|
write(" of ");
|
|
}
|
|
emit(node.expression);
|
|
emitToken(17 /* CloseParenToken */, node.expression.end);
|
|
emitEmbeddedStatement(node.statement);
|
|
}
|
|
function emitDownLevelForOfStatement(node) {
|
|
// The following ES6 code:
|
|
//
|
|
// for (let v of expr) { }
|
|
//
|
|
// should be emitted as
|
|
//
|
|
// for (let _i = 0, _a = expr; _i < _a.length; _i++) {
|
|
// let v = _a[_i];
|
|
// }
|
|
//
|
|
// where _a and _i are temps emitted to capture the RHS and the counter,
|
|
// respectively.
|
|
// When the left hand side is an expression instead of a let declaration,
|
|
// the "let v" is not emitted.
|
|
// When the left hand side is a let/const, the v is renamed if there is
|
|
// another v in scope.
|
|
// Note that all assignments to the LHS are emitted in the body, including
|
|
// all destructuring.
|
|
// Note also that because an extra statement is needed to assign to the LHS,
|
|
// for-of bodies are always emitted as blocks.
|
|
var endPos = emitToken(82 /* ForKeyword */, node.pos);
|
|
write(" ");
|
|
endPos = emitToken(16 /* OpenParenToken */, endPos);
|
|
// Do not emit the LHS let declaration yet, because it might contain destructuring.
|
|
// Do not call recordTempDeclaration because we are declaring the temps
|
|
// right here. Recording means they will be declared later.
|
|
// In the case where the user wrote an identifier as the RHS, like this:
|
|
//
|
|
// for (let v of arr) { }
|
|
//
|
|
// we don't want to emit a temporary variable for the RHS, just use it directly.
|
|
var rhsIsIdentifier = node.expression.kind === 65 /* Identifier */;
|
|
var counter = createTempVariable(268435456 /* _i */);
|
|
var rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(0 /* Auto */);
|
|
// This is the let keyword for the counter and rhsReference. The let keyword for
|
|
// the LHS will be emitted inside the body.
|
|
emitStart(node.expression);
|
|
write("var ");
|
|
// _i = 0
|
|
emitNodeWithoutSourceMap(counter);
|
|
write(" = 0");
|
|
emitEnd(node.expression);
|
|
if (!rhsIsIdentifier) {
|
|
// , _a = expr
|
|
write(", ");
|
|
emitStart(node.expression);
|
|
emitNodeWithoutSourceMap(rhsReference);
|
|
write(" = ");
|
|
emitNodeWithoutSourceMap(node.expression);
|
|
emitEnd(node.expression);
|
|
}
|
|
write("; ");
|
|
// _i < _a.length;
|
|
emitStart(node.initializer);
|
|
emitNodeWithoutSourceMap(counter);
|
|
write(" < ");
|
|
emitNodeWithoutSourceMap(rhsReference);
|
|
write(".length");
|
|
emitEnd(node.initializer);
|
|
write("; ");
|
|
// _i++)
|
|
emitStart(node.initializer);
|
|
emitNodeWithoutSourceMap(counter);
|
|
write("++");
|
|
emitEnd(node.initializer);
|
|
emitToken(17 /* CloseParenToken */, node.expression.end);
|
|
// Body
|
|
write(" {");
|
|
writeLine();
|
|
increaseIndent();
|
|
// Initialize LHS
|
|
// let v = _a[_i];
|
|
var rhsIterationValue = createElementAccessExpression(rhsReference, counter);
|
|
emitStart(node.initializer);
|
|
if (node.initializer.kind === 199 /* VariableDeclarationList */) {
|
|
write("var ");
|
|
var variableDeclarationList = node.initializer;
|
|
if (variableDeclarationList.declarations.length > 0) {
|
|
var declaration = variableDeclarationList.declarations[0];
|
|
if (ts.isBindingPattern(declaration.name)) {
|
|
// This works whether the declaration is a var, let, or const.
|
|
// It will use rhsIterationValue _a[_i] as the initializer.
|
|
emitDestructuring(declaration, false, rhsIterationValue);
|
|
}
|
|
else {
|
|
// The following call does not include the initializer, so we have
|
|
// to emit it separately.
|
|
emitNodeWithoutSourceMap(declaration);
|
|
write(" = ");
|
|
emitNodeWithoutSourceMap(rhsIterationValue);
|
|
}
|
|
}
|
|
else {
|
|
// It's an empty declaration list. This can only happen in an error case, if the user wrote
|
|
// for (let of []) {}
|
|
emitNodeWithoutSourceMap(createTempVariable(0 /* Auto */));
|
|
write(" = ");
|
|
emitNodeWithoutSourceMap(rhsIterationValue);
|
|
}
|
|
}
|
|
else {
|
|
// Initializer is an expression. Emit the expression in the body, so that it's
|
|
// evaluated on every iteration.
|
|
var assignmentExpression = createBinaryExpression(node.initializer, 53 /* EqualsToken */, rhsIterationValue, false);
|
|
if (node.initializer.kind === 153 /* ArrayLiteralExpression */ || node.initializer.kind === 154 /* ObjectLiteralExpression */) {
|
|
// This is a destructuring pattern, so call emitDestructuring instead of emit. Calling emit will not work, because it will cause
|
|
// the BinaryExpression to be passed in instead of the expression statement, which will cause emitDestructuring to crash.
|
|
emitDestructuring(assignmentExpression, true, undefined);
|
|
}
|
|
else {
|
|
emitNodeWithoutSourceMap(assignmentExpression);
|
|
}
|
|
}
|
|
emitEnd(node.initializer);
|
|
write(";");
|
|
if (node.statement.kind === 179 /* Block */) {
|
|
emitLines(node.statement.statements);
|
|
}
|
|
else {
|
|
writeLine();
|
|
emit(node.statement);
|
|
}
|
|
writeLine();
|
|
decreaseIndent();
|
|
write("}");
|
|
}
|
|
function emitBreakOrContinueStatement(node) {
|
|
emitToken(node.kind === 190 /* BreakStatement */ ? 66 /* BreakKeyword */ : 71 /* ContinueKeyword */, node.pos);
|
|
emitOptional(" ", node.label);
|
|
write(";");
|
|
}
|
|
function emitReturnStatement(node) {
|
|
emitToken(90 /* ReturnKeyword */, node.pos);
|
|
emitOptional(" ", node.expression);
|
|
write(";");
|
|
}
|
|
function emitWithStatement(node) {
|
|
write("with (");
|
|
emit(node.expression);
|
|
write(")");
|
|
emitEmbeddedStatement(node.statement);
|
|
}
|
|
function emitSwitchStatement(node) {
|
|
var endPos = emitToken(92 /* SwitchKeyword */, node.pos);
|
|
write(" ");
|
|
emitToken(16 /* OpenParenToken */, endPos);
|
|
emit(node.expression);
|
|
endPos = emitToken(17 /* CloseParenToken */, node.expression.end);
|
|
write(" ");
|
|
emitCaseBlock(node.caseBlock, endPos);
|
|
}
|
|
function emitCaseBlock(node, startPos) {
|
|
emitToken(14 /* OpenBraceToken */, startPos);
|
|
increaseIndent();
|
|
emitLines(node.clauses);
|
|
decreaseIndent();
|
|
writeLine();
|
|
emitToken(15 /* CloseBraceToken */, node.clauses.end);
|
|
}
|
|
function nodeStartPositionsAreOnSameLine(node1, node2) {
|
|
return ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node1.pos)) ===
|
|
ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node2.pos));
|
|
}
|
|
function nodeEndPositionsAreOnSameLine(node1, node2) {
|
|
return ts.getLineOfLocalPosition(currentSourceFile, node1.end) ===
|
|
ts.getLineOfLocalPosition(currentSourceFile, node2.end);
|
|
}
|
|
function nodeEndIsOnSameLineAsNodeStart(node1, node2) {
|
|
return ts.getLineOfLocalPosition(currentSourceFile, node1.end) ===
|
|
ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node2.pos));
|
|
}
|
|
function emitCaseOrDefaultClause(node) {
|
|
if (node.kind === 220 /* CaseClause */) {
|
|
write("case ");
|
|
emit(node.expression);
|
|
write(":");
|
|
}
|
|
else {
|
|
write("default:");
|
|
}
|
|
if (node.statements.length === 1 && nodeStartPositionsAreOnSameLine(node, node.statements[0])) {
|
|
write(" ");
|
|
emit(node.statements[0]);
|
|
}
|
|
else {
|
|
increaseIndent();
|
|
emitLines(node.statements);
|
|
decreaseIndent();
|
|
}
|
|
}
|
|
function emitThrowStatement(node) {
|
|
write("throw ");
|
|
emit(node.expression);
|
|
write(";");
|
|
}
|
|
function emitTryStatement(node) {
|
|
write("try ");
|
|
emit(node.tryBlock);
|
|
emit(node.catchClause);
|
|
if (node.finallyBlock) {
|
|
writeLine();
|
|
write("finally ");
|
|
emit(node.finallyBlock);
|
|
}
|
|
}
|
|
function emitCatchClause(node) {
|
|
writeLine();
|
|
var endPos = emitToken(68 /* CatchKeyword */, node.pos);
|
|
write(" ");
|
|
emitToken(16 /* OpenParenToken */, endPos);
|
|
emit(node.variableDeclaration);
|
|
emitToken(17 /* CloseParenToken */, node.variableDeclaration ? node.variableDeclaration.end : endPos);
|
|
write(" ");
|
|
emitBlock(node.block);
|
|
}
|
|
function emitDebuggerStatement(node) {
|
|
emitToken(72 /* DebuggerKeyword */, node.pos);
|
|
write(";");
|
|
}
|
|
function emitLabelledStatement(node) {
|
|
emit(node.label);
|
|
write(": ");
|
|
emit(node.statement);
|
|
}
|
|
function getContainingModule(node) {
|
|
do {
|
|
node = node.parent;
|
|
} while (node && node.kind !== 205 /* ModuleDeclaration */);
|
|
return node;
|
|
}
|
|
function emitContainingModuleName(node) {
|
|
var container = getContainingModule(node);
|
|
write(container ? getGeneratedNameForNode(container) : "exports");
|
|
}
|
|
function emitModuleMemberName(node) {
|
|
emitStart(node.name);
|
|
if (ts.getCombinedNodeFlags(node) & 1 /* Export */) {
|
|
var container = getContainingModule(node);
|
|
if (container) {
|
|
write(getGeneratedNameForNode(container));
|
|
write(".");
|
|
}
|
|
else if (languageVersion < 2 /* ES6 */ && compilerOptions.module !== 3 /* System */) {
|
|
write("exports.");
|
|
}
|
|
}
|
|
emitNodeWithoutSourceMap(node.name);
|
|
emitEnd(node.name);
|
|
}
|
|
function createVoidZero() {
|
|
var zero = ts.createSynthesizedNode(7 /* NumericLiteral */);
|
|
zero.text = "0";
|
|
var result = ts.createSynthesizedNode(166 /* VoidExpression */);
|
|
result.expression = zero;
|
|
return result;
|
|
}
|
|
function emitExportMemberAssignment(node) {
|
|
if (node.flags & 1 /* Export */) {
|
|
writeLine();
|
|
emitStart(node);
|
|
if (compilerOptions.module === 3 /* System */) {
|
|
// emit export default <smth> as
|
|
// export("default", <smth>)
|
|
write(exportFunctionForFile + "(\"");
|
|
if (node.flags & 256 /* Default */) {
|
|
write("default");
|
|
}
|
|
else {
|
|
emitNodeWithoutSourceMap(node.name);
|
|
}
|
|
write("\", ");
|
|
emitDeclarationName(node);
|
|
write(")");
|
|
}
|
|
else {
|
|
if (node.flags & 256 /* Default */) {
|
|
if (languageVersion === 0 /* ES3 */) {
|
|
write("exports[\"default\"]");
|
|
}
|
|
else {
|
|
write("exports.default");
|
|
}
|
|
}
|
|
else {
|
|
emitModuleMemberName(node);
|
|
}
|
|
write(" = ");
|
|
emitDeclarationName(node);
|
|
}
|
|
emitEnd(node);
|
|
write(";");
|
|
}
|
|
}
|
|
function emitExportMemberAssignments(name) {
|
|
if (!exportEquals && exportSpecifiers && ts.hasProperty(exportSpecifiers, name.text)) {
|
|
for (var _i = 0, _a = exportSpecifiers[name.text]; _i < _a.length; _i++) {
|
|
var specifier = _a[_i];
|
|
writeLine();
|
|
emitStart(specifier.name);
|
|
if (compilerOptions.module === 3 /* System */) {
|
|
write(exportFunctionForFile + "(\"");
|
|
emitNodeWithoutSourceMap(specifier.name);
|
|
write("\", ");
|
|
emitExpressionIdentifier(name);
|
|
write(")");
|
|
}
|
|
else {
|
|
emitContainingModuleName(specifier);
|
|
write(".");
|
|
emitNodeWithoutSourceMap(specifier.name);
|
|
emitEnd(specifier.name);
|
|
write(" = ");
|
|
emitExpressionIdentifier(name);
|
|
}
|
|
write(";");
|
|
}
|
|
}
|
|
}
|
|
function emitDestructuring(root, isAssignmentExpressionStatement, value) {
|
|
var emitCount = 0;
|
|
// An exported declaration is actually emitted as an assignment (to a property on the module object), so
|
|
// temporary variables in an exported declaration need to have real declarations elsewhere
|
|
// Also temporary variables should be explicitly allocated for source level declarations when module target is system
|
|
// because actual variable declarations are hoisted
|
|
var canDefineTempVariablesInPlace = false;
|
|
if (root.kind === 198 /* VariableDeclaration */) {
|
|
var isExported = ts.getCombinedNodeFlags(root) & 1 /* Export */;
|
|
var isSourceLevelForSystemModuleKind = isSourceFileLevelDeclarationInSystemExternalModule(root, false);
|
|
canDefineTempVariablesInPlace = !isExported && !isSourceLevelForSystemModuleKind;
|
|
}
|
|
else if (root.kind === 129 /* Parameter */) {
|
|
canDefineTempVariablesInPlace = true;
|
|
}
|
|
if (root.kind === 169 /* BinaryExpression */) {
|
|
emitAssignmentExpression(root);
|
|
}
|
|
else {
|
|
ts.Debug.assert(!isAssignmentExpressionStatement);
|
|
emitBindingElement(root, value);
|
|
}
|
|
function emitAssignment(name, value) {
|
|
if (emitCount++) {
|
|
write(", ");
|
|
}
|
|
renameNonTopLevelLetAndConst(name);
|
|
var isVariableDeclarationOrBindingElement = name.parent && (name.parent.kind === 198 /* VariableDeclaration */ || name.parent.kind === 152 /* BindingElement */);
|
|
var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(name);
|
|
if (exportChanged) {
|
|
write(exportFunctionForFile + "(\"");
|
|
emitNodeWithoutSourceMap(name);
|
|
write("\", ");
|
|
}
|
|
if (isVariableDeclarationOrBindingElement) {
|
|
emitModuleMemberName(name.parent);
|
|
}
|
|
else {
|
|
emit(name);
|
|
}
|
|
write(" = ");
|
|
emit(value);
|
|
if (exportChanged) {
|
|
write(")");
|
|
}
|
|
}
|
|
function ensureIdentifier(expr) {
|
|
if (expr.kind !== 65 /* Identifier */) {
|
|
var identifier = createTempVariable(0 /* Auto */);
|
|
if (!canDefineTempVariablesInPlace) {
|
|
recordTempDeclaration(identifier);
|
|
}
|
|
emitAssignment(identifier, expr);
|
|
expr = identifier;
|
|
}
|
|
return expr;
|
|
}
|
|
function createDefaultValueCheck(value, defaultValue) {
|
|
// The value expression will be evaluated twice, so for anything but a simple identifier
|
|
// we need to generate a temporary variable
|
|
value = ensureIdentifier(value);
|
|
// Return the expression 'value === void 0 ? defaultValue : value'
|
|
var equals = ts.createSynthesizedNode(169 /* BinaryExpression */);
|
|
equals.left = value;
|
|
equals.operatorToken = ts.createSynthesizedNode(30 /* EqualsEqualsEqualsToken */);
|
|
equals.right = createVoidZero();
|
|
return createConditionalExpression(equals, defaultValue, value);
|
|
}
|
|
function createConditionalExpression(condition, whenTrue, whenFalse) {
|
|
var cond = ts.createSynthesizedNode(170 /* ConditionalExpression */);
|
|
cond.condition = condition;
|
|
cond.questionToken = ts.createSynthesizedNode(50 /* QuestionToken */);
|
|
cond.whenTrue = whenTrue;
|
|
cond.colonToken = ts.createSynthesizedNode(51 /* ColonToken */);
|
|
cond.whenFalse = whenFalse;
|
|
return cond;
|
|
}
|
|
function createNumericLiteral(value) {
|
|
var node = ts.createSynthesizedNode(7 /* NumericLiteral */);
|
|
node.text = "" + value;
|
|
return node;
|
|
}
|
|
function createPropertyAccessForDestructuringProperty(object, propName) {
|
|
if (propName.kind !== 65 /* Identifier */) {
|
|
return createElementAccessExpression(object, propName);
|
|
}
|
|
return createPropertyAccessExpression(object, propName);
|
|
}
|
|
function createSliceCall(value, sliceIndex) {
|
|
var call = ts.createSynthesizedNode(157 /* CallExpression */);
|
|
var sliceIdentifier = ts.createSynthesizedNode(65 /* Identifier */);
|
|
sliceIdentifier.text = "slice";
|
|
call.expression = createPropertyAccessExpression(value, sliceIdentifier);
|
|
call.arguments = ts.createSynthesizedNodeArray();
|
|
call.arguments[0] = createNumericLiteral(sliceIndex);
|
|
return call;
|
|
}
|
|
function emitObjectLiteralAssignment(target, value) {
|
|
var properties = target.properties;
|
|
if (properties.length !== 1) {
|
|
// For anything but a single element destructuring we need to generate a temporary
|
|
// to ensure value is evaluated exactly once.
|
|
value = ensureIdentifier(value);
|
|
}
|
|
for (var _i = 0; _i < properties.length; _i++) {
|
|
var p = properties[_i];
|
|
if (p.kind === 224 /* PropertyAssignment */ || p.kind === 225 /* ShorthandPropertyAssignment */) {
|
|
// TODO(andersh): Computed property support
|
|
var propName = (p.name);
|
|
emitDestructuringAssignment(p.initializer || propName, createPropertyAccessForDestructuringProperty(value, propName));
|
|
}
|
|
}
|
|
}
|
|
function emitArrayLiteralAssignment(target, value) {
|
|
var elements = target.elements;
|
|
if (elements.length !== 1) {
|
|
// For anything but a single element destructuring we need to generate a temporary
|
|
// to ensure value is evaluated exactly once.
|
|
value = ensureIdentifier(value);
|
|
}
|
|
for (var i = 0; i < elements.length; i++) {
|
|
var e = elements[i];
|
|
if (e.kind !== 175 /* OmittedExpression */) {
|
|
if (e.kind !== 173 /* SpreadElementExpression */) {
|
|
emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i)));
|
|
}
|
|
else if (i === elements.length - 1) {
|
|
emitDestructuringAssignment(e.expression, createSliceCall(value, i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function emitDestructuringAssignment(target, value) {
|
|
if (target.kind === 169 /* BinaryExpression */ && target.operatorToken.kind === 53 /* EqualsToken */) {
|
|
value = createDefaultValueCheck(value, target.right);
|
|
target = target.left;
|
|
}
|
|
if (target.kind === 154 /* ObjectLiteralExpression */) {
|
|
emitObjectLiteralAssignment(target, value);
|
|
}
|
|
else if (target.kind === 153 /* ArrayLiteralExpression */) {
|
|
emitArrayLiteralAssignment(target, value);
|
|
}
|
|
else {
|
|
emitAssignment(target, value);
|
|
}
|
|
}
|
|
function emitAssignmentExpression(root) {
|
|
var target = root.left;
|
|
var value = root.right;
|
|
if (isAssignmentExpressionStatement) {
|
|
emitDestructuringAssignment(target, value);
|
|
}
|
|
else {
|
|
if (root.parent.kind !== 161 /* ParenthesizedExpression */) {
|
|
write("(");
|
|
}
|
|
value = ensureIdentifier(value);
|
|
emitDestructuringAssignment(target, value);
|
|
write(", ");
|
|
emit(value);
|
|
if (root.parent.kind !== 161 /* ParenthesizedExpression */) {
|
|
write(")");
|
|
}
|
|
}
|
|
}
|
|
function emitBindingElement(target, value) {
|
|
if (target.initializer) {
|
|
// Combine value and initializer
|
|
value = value ? createDefaultValueCheck(value, target.initializer) : target.initializer;
|
|
}
|
|
else if (!value) {
|
|
// Use 'void 0' in absence of value and initializer
|
|
value = createVoidZero();
|
|
}
|
|
if (ts.isBindingPattern(target.name)) {
|
|
var pattern = target.name;
|
|
var elements = pattern.elements;
|
|
if (elements.length !== 1) {
|
|
// For anything but a single element destructuring we need to generate a temporary
|
|
// to ensure value is evaluated exactly once.
|
|
value = ensureIdentifier(value);
|
|
}
|
|
for (var i = 0; i < elements.length; i++) {
|
|
var element = elements[i];
|
|
if (pattern.kind === 150 /* ObjectBindingPattern */) {
|
|
// Rewrite element to a declaration with an initializer that fetches property
|
|
var propName = element.propertyName || element.name;
|
|
emitBindingElement(element, createPropertyAccessForDestructuringProperty(value, propName));
|
|
}
|
|
else if (element.kind !== 175 /* OmittedExpression */) {
|
|
if (!element.dotDotDotToken) {
|
|
// Rewrite element to a declaration that accesses array element at index i
|
|
emitBindingElement(element, createElementAccessExpression(value, createNumericLiteral(i)));
|
|
}
|
|
else if (i === elements.length - 1) {
|
|
emitBindingElement(element, createSliceCall(value, i));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
emitAssignment(target.name, value);
|
|
}
|
|
}
|
|
}
|
|
function emitVariableDeclaration(node) {
|
|
if (ts.isBindingPattern(node.name)) {
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
emitDestructuring(node, false);
|
|
}
|
|
else {
|
|
emit(node.name);
|
|
emitOptional(" = ", node.initializer);
|
|
}
|
|
}
|
|
else {
|
|
renameNonTopLevelLetAndConst(node.name);
|
|
var initializer = node.initializer;
|
|
if (!initializer && languageVersion < 2 /* ES6 */) {
|
|
// downlevel emit for non-initialized let bindings defined in loops
|
|
// for (...) { let x; }
|
|
// should be
|
|
// for (...) { var <some-uniqie-name> = void 0; }
|
|
// this is necessary to preserve ES6 semantic in scenarios like
|
|
// for (...) { let x; console.log(x); x = 1 } // assignment on one iteration should not affect other iterations
|
|
var isUninitializedLet = (resolver.getNodeCheckFlags(node) & 256 /* BlockScopedBindingInLoop */) &&
|
|
(getCombinedFlagsForIdentifier(node.name) & 4096 /* Let */);
|
|
// NOTE: default initialization should not be added to let bindings in for-in\for-of statements
|
|
if (isUninitializedLet &&
|
|
node.parent.parent.kind !== 187 /* ForInStatement */ &&
|
|
node.parent.parent.kind !== 188 /* ForOfStatement */) {
|
|
initializer = createVoidZero();
|
|
}
|
|
}
|
|
var exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.name);
|
|
if (exportChanged) {
|
|
write(exportFunctionForFile + "(\"");
|
|
emitNodeWithoutSourceMap(node.name);
|
|
write("\", ");
|
|
}
|
|
emitModuleMemberName(node);
|
|
emitOptional(" = ", initializer);
|
|
if (exportChanged) {
|
|
write(")");
|
|
}
|
|
}
|
|
}
|
|
function emitExportVariableAssignments(node) {
|
|
if (node.kind === 175 /* OmittedExpression */) {
|
|
return;
|
|
}
|
|
var name = node.name;
|
|
if (name.kind === 65 /* Identifier */) {
|
|
emitExportMemberAssignments(name);
|
|
}
|
|
else if (ts.isBindingPattern(name)) {
|
|
ts.forEach(name.elements, emitExportVariableAssignments);
|
|
}
|
|
}
|
|
function getCombinedFlagsForIdentifier(node) {
|
|
if (!node.parent || (node.parent.kind !== 198 /* VariableDeclaration */ && node.parent.kind !== 152 /* BindingElement */)) {
|
|
return 0;
|
|
}
|
|
return ts.getCombinedNodeFlags(node.parent);
|
|
}
|
|
function renameNonTopLevelLetAndConst(node) {
|
|
// do not rename if
|
|
// - language version is ES6+
|
|
// - node is synthesized
|
|
// - node is not identifier (can happen when tree is malformed)
|
|
// - node is definitely not name of variable declaration.
|
|
// it still can be part of parameter declaration, this check will be done next
|
|
if (languageVersion >= 2 /* ES6 */ ||
|
|
ts.nodeIsSynthesized(node) ||
|
|
node.kind !== 65 /* Identifier */ ||
|
|
(node.parent.kind !== 198 /* VariableDeclaration */ && node.parent.kind !== 152 /* BindingElement */)) {
|
|
return;
|
|
}
|
|
var combinedFlags = getCombinedFlagsForIdentifier(node);
|
|
if (((combinedFlags & 12288 /* BlockScoped */) === 0) || combinedFlags & 1 /* Export */) {
|
|
// do not rename exported or non-block scoped variables
|
|
return;
|
|
}
|
|
// here it is known that node is a block scoped variable
|
|
var list = ts.getAncestor(node, 199 /* VariableDeclarationList */);
|
|
if (list.parent.kind === 180 /* VariableStatement */) {
|
|
var isSourceFileLevelBinding = list.parent.parent.kind === 227 /* SourceFile */;
|
|
var isModuleLevelBinding = list.parent.parent.kind === 206 /* ModuleBlock */;
|
|
var isFunctionLevelBinding = list.parent.parent.kind === 179 /* Block */ && ts.isFunctionLike(list.parent.parent.parent);
|
|
if (isSourceFileLevelBinding || isModuleLevelBinding || isFunctionLevelBinding) {
|
|
return;
|
|
}
|
|
}
|
|
var blockScopeContainer = ts.getEnclosingBlockScopeContainer(node);
|
|
var parent = blockScopeContainer.kind === 227 /* SourceFile */
|
|
? blockScopeContainer
|
|
: blockScopeContainer.parent;
|
|
if (resolver.resolvesToSomeValue(parent, node.text)) {
|
|
var variableId = resolver.getBlockScopedVariableId(node);
|
|
if (!blockScopedVariableToGeneratedName) {
|
|
blockScopedVariableToGeneratedName = [];
|
|
}
|
|
var generatedName = makeUniqueName(node.text);
|
|
blockScopedVariableToGeneratedName[variableId] = generatedName;
|
|
}
|
|
}
|
|
function isES6ExportedDeclaration(node) {
|
|
return !!(node.flags & 1 /* Export */) &&
|
|
languageVersion >= 2 /* ES6 */ &&
|
|
node.parent.kind === 227 /* SourceFile */;
|
|
}
|
|
function emitVariableStatement(node) {
|
|
var startIsEmitted = true;
|
|
if (!(node.flags & 1 /* Export */)) {
|
|
startIsEmitted = tryEmitStartOfVariableDeclarationList(node.declarationList);
|
|
}
|
|
else if (isES6ExportedDeclaration(node)) {
|
|
// Exported ES6 module member
|
|
write("export ");
|
|
startIsEmitted = tryEmitStartOfVariableDeclarationList(node.declarationList);
|
|
}
|
|
if (startIsEmitted) {
|
|
emitCommaList(node.declarationList.declarations);
|
|
write(";");
|
|
}
|
|
else {
|
|
var atLeastOneItem = emitVariableDeclarationListSkippingUninitializedEntries(node.declarationList);
|
|
if (atLeastOneItem) {
|
|
write(";");
|
|
}
|
|
}
|
|
if (languageVersion < 2 /* ES6 */ && node.parent === currentSourceFile) {
|
|
ts.forEach(node.declarationList.declarations, emitExportVariableAssignments);
|
|
}
|
|
}
|
|
function emitParameter(node) {
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
if (ts.isBindingPattern(node.name)) {
|
|
var name_5 = createTempVariable(0 /* Auto */);
|
|
if (!tempParameters) {
|
|
tempParameters = [];
|
|
}
|
|
tempParameters.push(name_5);
|
|
emit(name_5);
|
|
}
|
|
else {
|
|
emit(node.name);
|
|
}
|
|
}
|
|
else {
|
|
if (node.dotDotDotToken) {
|
|
write("...");
|
|
}
|
|
emit(node.name);
|
|
emitOptional(" = ", node.initializer);
|
|
}
|
|
}
|
|
function emitDefaultValueAssignments(node) {
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
var tempIndex = 0;
|
|
ts.forEach(node.parameters, function (p) {
|
|
// A rest parameter cannot have a binding pattern or an initializer,
|
|
// so let's just ignore it.
|
|
if (p.dotDotDotToken) {
|
|
return;
|
|
}
|
|
if (ts.isBindingPattern(p.name)) {
|
|
writeLine();
|
|
write("var ");
|
|
emitDestructuring(p, false, tempParameters[tempIndex]);
|
|
write(";");
|
|
tempIndex++;
|
|
}
|
|
else if (p.initializer) {
|
|
writeLine();
|
|
emitStart(p);
|
|
write("if (");
|
|
emitNodeWithoutSourceMap(p.name);
|
|
write(" === void 0)");
|
|
emitEnd(p);
|
|
write(" { ");
|
|
emitStart(p);
|
|
emitNodeWithoutSourceMap(p.name);
|
|
write(" = ");
|
|
emitNodeWithoutSourceMap(p.initializer);
|
|
emitEnd(p);
|
|
write("; }");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
function emitRestParameter(node) {
|
|
if (languageVersion < 2 /* ES6 */ && ts.hasRestParameters(node)) {
|
|
var restIndex = node.parameters.length - 1;
|
|
var restParam = node.parameters[restIndex];
|
|
// A rest parameter cannot have a binding pattern, so let's just ignore it if it does.
|
|
if (ts.isBindingPattern(restParam.name)) {
|
|
return;
|
|
}
|
|
var tempName = createTempVariable(268435456 /* _i */).text;
|
|
writeLine();
|
|
emitLeadingComments(restParam);
|
|
emitStart(restParam);
|
|
write("var ");
|
|
emitNodeWithoutSourceMap(restParam.name);
|
|
write(" = [];");
|
|
emitEnd(restParam);
|
|
emitTrailingComments(restParam);
|
|
writeLine();
|
|
write("for (");
|
|
emitStart(restParam);
|
|
write("var " + tempName + " = " + restIndex + ";");
|
|
emitEnd(restParam);
|
|
write(" ");
|
|
emitStart(restParam);
|
|
write(tempName + " < arguments.length;");
|
|
emitEnd(restParam);
|
|
write(" ");
|
|
emitStart(restParam);
|
|
write(tempName + "++");
|
|
emitEnd(restParam);
|
|
write(") {");
|
|
increaseIndent();
|
|
writeLine();
|
|
emitStart(restParam);
|
|
emitNodeWithoutSourceMap(restParam.name);
|
|
write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];");
|
|
emitEnd(restParam);
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("}");
|
|
}
|
|
}
|
|
function emitAccessor(node) {
|
|
write(node.kind === 136 /* GetAccessor */ ? "get " : "set ");
|
|
emit(node.name, false);
|
|
emitSignatureAndBody(node);
|
|
}
|
|
function shouldEmitAsArrowFunction(node) {
|
|
return node.kind === 163 /* ArrowFunction */ && languageVersion >= 2 /* ES6 */;
|
|
}
|
|
function emitDeclarationName(node) {
|
|
if (node.name) {
|
|
emitNodeWithoutSourceMap(node.name);
|
|
}
|
|
else {
|
|
write(getGeneratedNameForNode(node));
|
|
}
|
|
}
|
|
function shouldEmitFunctionName(node) {
|
|
if (node.kind === 162 /* FunctionExpression */) {
|
|
// Emit name if one is present
|
|
return !!node.name;
|
|
}
|
|
if (node.kind === 200 /* FunctionDeclaration */) {
|
|
// Emit name if one is present, or emit generated name in down-level case (for export default case)
|
|
return !!node.name || languageVersion < 2 /* ES6 */;
|
|
}
|
|
}
|
|
function emitFunctionDeclaration(node) {
|
|
if (ts.nodeIsMissing(node.body)) {
|
|
return emitOnlyPinnedOrTripleSlashComments(node);
|
|
}
|
|
if (node.kind !== 134 /* MethodDeclaration */ && node.kind !== 133 /* MethodSignature */) {
|
|
// Methods will emit the comments as part of emitting method declaration
|
|
emitLeadingComments(node);
|
|
}
|
|
// For targeting below es6, emit functions-like declaration including arrow function using function keyword.
|
|
// When targeting ES6, emit arrow function natively in ES6 by omitting function keyword and using fat arrow instead
|
|
if (!shouldEmitAsArrowFunction(node)) {
|
|
if (isES6ExportedDeclaration(node)) {
|
|
write("export ");
|
|
if (node.flags & 256 /* Default */) {
|
|
write("default ");
|
|
}
|
|
}
|
|
write("function");
|
|
if (languageVersion >= 2 /* ES6 */ && node.asteriskToken) {
|
|
write("*");
|
|
}
|
|
write(" ");
|
|
}
|
|
if (shouldEmitFunctionName(node)) {
|
|
emitDeclarationName(node);
|
|
}
|
|
emitSignatureAndBody(node);
|
|
if (languageVersion < 2 /* ES6 */ && node.kind === 200 /* FunctionDeclaration */ && node.parent === currentSourceFile && node.name) {
|
|
emitExportMemberAssignments(node.name);
|
|
}
|
|
if (node.kind !== 134 /* MethodDeclaration */ && node.kind !== 133 /* MethodSignature */) {
|
|
emitTrailingComments(node);
|
|
}
|
|
}
|
|
function emitCaptureThisForNodeIfNecessary(node) {
|
|
if (resolver.getNodeCheckFlags(node) & 4 /* CaptureThis */) {
|
|
writeLine();
|
|
emitStart(node);
|
|
write("var _this = this;");
|
|
emitEnd(node);
|
|
}
|
|
}
|
|
function emitSignatureParameters(node) {
|
|
increaseIndent();
|
|
write("(");
|
|
if (node) {
|
|
var parameters = node.parameters;
|
|
var omitCount = languageVersion < 2 /* ES6 */ && ts.hasRestParameters(node) ? 1 : 0;
|
|
emitList(parameters, 0, parameters.length - omitCount, false, false);
|
|
}
|
|
write(")");
|
|
decreaseIndent();
|
|
}
|
|
function emitSignatureParametersForArrow(node) {
|
|
// Check whether the parameter list needs parentheses and preserve no-parenthesis
|
|
if (node.parameters.length === 1 && node.pos === node.parameters[0].pos) {
|
|
emit(node.parameters[0]);
|
|
return;
|
|
}
|
|
emitSignatureParameters(node);
|
|
}
|
|
function emitSignatureAndBody(node) {
|
|
var saveTempFlags = tempFlags;
|
|
var saveTempVariables = tempVariables;
|
|
var saveTempParameters = tempParameters;
|
|
tempFlags = 0;
|
|
tempVariables = undefined;
|
|
tempParameters = undefined;
|
|
// When targeting ES6, emit arrow function natively in ES6
|
|
if (shouldEmitAsArrowFunction(node)) {
|
|
emitSignatureParametersForArrow(node);
|
|
write(" =>");
|
|
}
|
|
else {
|
|
emitSignatureParameters(node);
|
|
}
|
|
if (!node.body) {
|
|
// There can be no body when there are parse errors. Just emit an empty block
|
|
// in that case.
|
|
write(" { }");
|
|
}
|
|
else if (node.body.kind === 179 /* Block */) {
|
|
emitBlockFunctionBody(node, node.body);
|
|
}
|
|
else {
|
|
emitExpressionFunctionBody(node, node.body);
|
|
}
|
|
if (!isES6ExportedDeclaration(node)) {
|
|
emitExportMemberAssignment(node);
|
|
}
|
|
tempFlags = saveTempFlags;
|
|
tempVariables = saveTempVariables;
|
|
tempParameters = saveTempParameters;
|
|
}
|
|
// Returns true if any preamble code was emitted.
|
|
function emitFunctionBodyPreamble(node) {
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
emitDefaultValueAssignments(node);
|
|
emitRestParameter(node);
|
|
}
|
|
function emitExpressionFunctionBody(node, body) {
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
emitDownLevelExpressionFunctionBody(node, body);
|
|
return;
|
|
}
|
|
// For es6 and higher we can emit the expression as is. However, in the case
|
|
// where the expression might end up looking like a block when emitted, we'll
|
|
// also wrap it in parentheses first. For example if you have: a => <foo>{}
|
|
// then we need to generate: a => ({})
|
|
write(" ");
|
|
// Unwrap all type assertions.
|
|
var current = body;
|
|
while (current.kind === 160 /* TypeAssertionExpression */) {
|
|
current = current.expression;
|
|
}
|
|
emitParenthesizedIf(body, current.kind === 154 /* ObjectLiteralExpression */);
|
|
}
|
|
function emitDownLevelExpressionFunctionBody(node, body) {
|
|
write(" {");
|
|
scopeEmitStart(node);
|
|
increaseIndent();
|
|
var outPos = writer.getTextPos();
|
|
emitDetachedComments(node.body);
|
|
emitFunctionBodyPreamble(node);
|
|
var preambleEmitted = writer.getTextPos() !== outPos;
|
|
decreaseIndent();
|
|
// If we didn't have to emit any preamble code, then attempt to keep the arrow
|
|
// function on one line.
|
|
if (!preambleEmitted && nodeStartPositionsAreOnSameLine(node, body)) {
|
|
write(" ");
|
|
emitStart(body);
|
|
write("return ");
|
|
emit(body);
|
|
emitEnd(body);
|
|
write(";");
|
|
emitTempDeclarations(false);
|
|
write(" ");
|
|
}
|
|
else {
|
|
increaseIndent();
|
|
writeLine();
|
|
emitLeadingComments(node.body);
|
|
write("return ");
|
|
emit(body);
|
|
write(";");
|
|
emitTrailingComments(node.body);
|
|
emitTempDeclarations(true);
|
|
decreaseIndent();
|
|
writeLine();
|
|
}
|
|
emitStart(node.body);
|
|
write("}");
|
|
emitEnd(node.body);
|
|
scopeEmitEnd();
|
|
}
|
|
function emitBlockFunctionBody(node, body) {
|
|
write(" {");
|
|
scopeEmitStart(node);
|
|
var initialTextPos = writer.getTextPos();
|
|
increaseIndent();
|
|
emitDetachedComments(body.statements);
|
|
// Emit all the directive prologues (like "use strict"). These have to come before
|
|
// any other preamble code we write (like parameter initializers).
|
|
var startIndex = emitDirectivePrologues(body.statements, true);
|
|
emitFunctionBodyPreamble(node);
|
|
decreaseIndent();
|
|
var preambleEmitted = writer.getTextPos() !== initialTextPos;
|
|
if (!preambleEmitted && nodeEndIsOnSameLineAsNodeStart(body, body)) {
|
|
for (var _i = 0, _a = body.statements; _i < _a.length; _i++) {
|
|
var statement = _a[_i];
|
|
write(" ");
|
|
emit(statement);
|
|
}
|
|
emitTempDeclarations(false);
|
|
write(" ");
|
|
emitLeadingCommentsOfPosition(body.statements.end);
|
|
}
|
|
else {
|
|
increaseIndent();
|
|
emitLinesStartingAt(body.statements, startIndex);
|
|
emitTempDeclarations(true);
|
|
writeLine();
|
|
emitLeadingCommentsOfPosition(body.statements.end);
|
|
decreaseIndent();
|
|
}
|
|
emitToken(15 /* CloseBraceToken */, body.statements.end);
|
|
scopeEmitEnd();
|
|
}
|
|
function findInitialSuperCall(ctor) {
|
|
if (ctor.body) {
|
|
var statement = ctor.body.statements[0];
|
|
if (statement && statement.kind === 182 /* ExpressionStatement */) {
|
|
var expr = statement.expression;
|
|
if (expr && expr.kind === 157 /* CallExpression */) {
|
|
var func = expr.expression;
|
|
if (func && func.kind === 91 /* SuperKeyword */) {
|
|
return statement;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function emitParameterPropertyAssignments(node) {
|
|
ts.forEach(node.parameters, function (param) {
|
|
if (param.flags & 112 /* AccessibilityModifier */) {
|
|
writeLine();
|
|
emitStart(param);
|
|
emitStart(param.name);
|
|
write("this.");
|
|
emitNodeWithoutSourceMap(param.name);
|
|
emitEnd(param.name);
|
|
write(" = ");
|
|
emit(param.name);
|
|
write(";");
|
|
emitEnd(param);
|
|
}
|
|
});
|
|
}
|
|
function emitMemberAccessForPropertyName(memberName) {
|
|
// TODO: (jfreeman,drosen): comment on why this is emitNodeWithoutSourceMap instead of emit here.
|
|
if (memberName.kind === 8 /* StringLiteral */ || memberName.kind === 7 /* NumericLiteral */) {
|
|
write("[");
|
|
emitNodeWithoutSourceMap(memberName);
|
|
write("]");
|
|
}
|
|
else if (memberName.kind === 127 /* ComputedPropertyName */) {
|
|
emitComputedPropertyName(memberName);
|
|
}
|
|
else {
|
|
write(".");
|
|
emitNodeWithoutSourceMap(memberName);
|
|
}
|
|
}
|
|
function getInitializedProperties(node, static) {
|
|
var properties = [];
|
|
for (var _i = 0, _a = node.members; _i < _a.length; _i++) {
|
|
var member = _a[_i];
|
|
if (member.kind === 132 /* PropertyDeclaration */ && static === ((member.flags & 128 /* Static */) !== 0) && member.initializer) {
|
|
properties.push(member);
|
|
}
|
|
}
|
|
return properties;
|
|
}
|
|
function emitPropertyDeclarations(node, properties) {
|
|
for (var _i = 0; _i < properties.length; _i++) {
|
|
var property = properties[_i];
|
|
emitPropertyDeclaration(node, property);
|
|
}
|
|
}
|
|
function emitPropertyDeclaration(node, property, receiver, isExpression) {
|
|
writeLine();
|
|
emitLeadingComments(property);
|
|
emitStart(property);
|
|
emitStart(property.name);
|
|
if (receiver) {
|
|
emit(receiver);
|
|
}
|
|
else {
|
|
if (property.flags & 128 /* Static */) {
|
|
emitDeclarationName(node);
|
|
}
|
|
else {
|
|
write("this");
|
|
}
|
|
}
|
|
emitMemberAccessForPropertyName(property.name);
|
|
emitEnd(property.name);
|
|
write(" = ");
|
|
emit(property.initializer);
|
|
if (!isExpression) {
|
|
write(";");
|
|
}
|
|
emitEnd(property);
|
|
emitTrailingComments(property);
|
|
}
|
|
function emitMemberFunctionsForES5AndLower(node) {
|
|
ts.forEach(node.members, function (member) {
|
|
if (member.kind === 178 /* SemicolonClassElement */) {
|
|
writeLine();
|
|
write(";");
|
|
}
|
|
else if (member.kind === 134 /* MethodDeclaration */ || node.kind === 133 /* MethodSignature */) {
|
|
if (!member.body) {
|
|
return emitOnlyPinnedOrTripleSlashComments(member);
|
|
}
|
|
writeLine();
|
|
emitLeadingComments(member);
|
|
emitStart(member);
|
|
emitStart(member.name);
|
|
emitClassMemberPrefix(node, member);
|
|
emitMemberAccessForPropertyName(member.name);
|
|
emitEnd(member.name);
|
|
write(" = ");
|
|
emitStart(member);
|
|
emitFunctionDeclaration(member);
|
|
emitEnd(member);
|
|
emitEnd(member);
|
|
write(";");
|
|
emitTrailingComments(member);
|
|
}
|
|
else if (member.kind === 136 /* GetAccessor */ || member.kind === 137 /* SetAccessor */) {
|
|
var accessors = ts.getAllAccessorDeclarations(node.members, member);
|
|
if (member === accessors.firstAccessor) {
|
|
writeLine();
|
|
emitStart(member);
|
|
write("Object.defineProperty(");
|
|
emitStart(member.name);
|
|
emitClassMemberPrefix(node, member);
|
|
write(", ");
|
|
emitExpressionForPropertyName(member.name);
|
|
emitEnd(member.name);
|
|
write(", {");
|
|
increaseIndent();
|
|
if (accessors.getAccessor) {
|
|
writeLine();
|
|
emitLeadingComments(accessors.getAccessor);
|
|
write("get: ");
|
|
emitStart(accessors.getAccessor);
|
|
write("function ");
|
|
emitSignatureAndBody(accessors.getAccessor);
|
|
emitEnd(accessors.getAccessor);
|
|
emitTrailingComments(accessors.getAccessor);
|
|
write(",");
|
|
}
|
|
if (accessors.setAccessor) {
|
|
writeLine();
|
|
emitLeadingComments(accessors.setAccessor);
|
|
write("set: ");
|
|
emitStart(accessors.setAccessor);
|
|
write("function ");
|
|
emitSignatureAndBody(accessors.setAccessor);
|
|
emitEnd(accessors.setAccessor);
|
|
emitTrailingComments(accessors.setAccessor);
|
|
write(",");
|
|
}
|
|
writeLine();
|
|
write("enumerable: true,");
|
|
writeLine();
|
|
write("configurable: true");
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("});");
|
|
emitEnd(member);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function emitMemberFunctionsForES6AndHigher(node) {
|
|
for (var _i = 0, _a = node.members; _i < _a.length; _i++) {
|
|
var member = _a[_i];
|
|
if ((member.kind === 134 /* MethodDeclaration */ || node.kind === 133 /* MethodSignature */) && !member.body) {
|
|
emitOnlyPinnedOrTripleSlashComments(member);
|
|
}
|
|
else if (member.kind === 134 /* MethodDeclaration */ ||
|
|
member.kind === 136 /* GetAccessor */ ||
|
|
member.kind === 137 /* SetAccessor */) {
|
|
writeLine();
|
|
emitLeadingComments(member);
|
|
emitStart(member);
|
|
if (member.flags & 128 /* Static */) {
|
|
write("static ");
|
|
}
|
|
if (member.kind === 136 /* GetAccessor */) {
|
|
write("get ");
|
|
}
|
|
else if (member.kind === 137 /* SetAccessor */) {
|
|
write("set ");
|
|
}
|
|
if (member.asteriskToken) {
|
|
write("*");
|
|
}
|
|
emit(member.name);
|
|
emitSignatureAndBody(member);
|
|
emitEnd(member);
|
|
emitTrailingComments(member);
|
|
}
|
|
else if (member.kind === 178 /* SemicolonClassElement */) {
|
|
writeLine();
|
|
write(";");
|
|
}
|
|
}
|
|
}
|
|
function emitConstructor(node, baseTypeElement) {
|
|
var saveTempFlags = tempFlags;
|
|
var saveTempVariables = tempVariables;
|
|
var saveTempParameters = tempParameters;
|
|
tempFlags = 0;
|
|
tempVariables = undefined;
|
|
tempParameters = undefined;
|
|
emitConstructorWorker(node, baseTypeElement);
|
|
tempFlags = saveTempFlags;
|
|
tempVariables = saveTempVariables;
|
|
tempParameters = saveTempParameters;
|
|
}
|
|
function emitConstructorWorker(node, baseTypeElement) {
|
|
// Check if we have property assignment inside class declaration.
|
|
// If there is property assignment, we need to emit constructor whether users define it or not
|
|
// If there is no property assignment, we can omit constructor if users do not define it
|
|
var hasInstancePropertyWithInitializer = false;
|
|
// Emit the constructor overload pinned comments
|
|
ts.forEach(node.members, function (member) {
|
|
if (member.kind === 135 /* Constructor */ && !member.body) {
|
|
emitOnlyPinnedOrTripleSlashComments(member);
|
|
}
|
|
// Check if there is any non-static property assignment
|
|
if (member.kind === 132 /* PropertyDeclaration */ && member.initializer && (member.flags & 128 /* Static */) === 0) {
|
|
hasInstancePropertyWithInitializer = true;
|
|
}
|
|
});
|
|
var ctor = ts.getFirstConstructorWithBody(node);
|
|
// For target ES6 and above, if there is no user-defined constructor and there is no property assignment
|
|
// do not emit constructor in class declaration.
|
|
if (languageVersion >= 2 /* ES6 */ && !ctor && !hasInstancePropertyWithInitializer) {
|
|
return;
|
|
}
|
|
if (ctor) {
|
|
emitLeadingComments(ctor);
|
|
}
|
|
emitStart(ctor || node);
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
write("function ");
|
|
emitDeclarationName(node);
|
|
emitSignatureParameters(ctor);
|
|
}
|
|
else {
|
|
write("constructor");
|
|
if (ctor) {
|
|
emitSignatureParameters(ctor);
|
|
}
|
|
else {
|
|
// Based on EcmaScript6 section 14.5.14: Runtime Semantics: ClassDefinitionEvaluation.
|
|
// If constructor is empty, then,
|
|
// If ClassHeritageopt is present, then
|
|
// Let constructor be the result of parsing the String "constructor(... args){ super (...args);}" using the syntactic grammar with the goal symbol MethodDefinition.
|
|
// Else,
|
|
// Let constructor be the result of parsing the String "constructor( ){ }" using the syntactic grammar with the goal symbol MethodDefinition
|
|
if (baseTypeElement) {
|
|
write("(...args)");
|
|
}
|
|
else {
|
|
write("()");
|
|
}
|
|
}
|
|
}
|
|
write(" {");
|
|
scopeEmitStart(node, "constructor");
|
|
increaseIndent();
|
|
if (ctor) {
|
|
emitDetachedComments(ctor.body.statements);
|
|
}
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
if (ctor) {
|
|
emitDefaultValueAssignments(ctor);
|
|
emitRestParameter(ctor);
|
|
if (baseTypeElement) {
|
|
var superCall = findInitialSuperCall(ctor);
|
|
if (superCall) {
|
|
writeLine();
|
|
emit(superCall);
|
|
}
|
|
}
|
|
emitParameterPropertyAssignments(ctor);
|
|
}
|
|
else {
|
|
if (baseTypeElement) {
|
|
writeLine();
|
|
emitStart(baseTypeElement);
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
write("_super.apply(this, arguments);");
|
|
}
|
|
else {
|
|
write("super(...args);");
|
|
}
|
|
emitEnd(baseTypeElement);
|
|
}
|
|
}
|
|
emitPropertyDeclarations(node, getInitializedProperties(node, false));
|
|
if (ctor) {
|
|
var statements = ctor.body.statements;
|
|
if (superCall) {
|
|
statements = statements.slice(1);
|
|
}
|
|
emitLines(statements);
|
|
}
|
|
emitTempDeclarations(true);
|
|
writeLine();
|
|
if (ctor) {
|
|
emitLeadingCommentsOfPosition(ctor.body.statements.end);
|
|
}
|
|
decreaseIndent();
|
|
emitToken(15 /* CloseBraceToken */, ctor ? ctor.body.statements.end : node.members.end);
|
|
scopeEmitEnd();
|
|
emitEnd(ctor || node);
|
|
if (ctor) {
|
|
emitTrailingComments(ctor);
|
|
}
|
|
}
|
|
function emitClassExpression(node) {
|
|
return emitClassLikeDeclaration(node);
|
|
}
|
|
function emitClassDeclaration(node) {
|
|
return emitClassLikeDeclaration(node);
|
|
}
|
|
function emitClassLikeDeclaration(node) {
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
emitClassLikeDeclarationBelowES6(node);
|
|
}
|
|
else {
|
|
emitClassLikeDeclarationForES6AndHigher(node);
|
|
}
|
|
}
|
|
function emitClassLikeDeclarationForES6AndHigher(node) {
|
|
var thisNodeIsDecorated = ts.nodeIsDecorated(node);
|
|
if (node.kind === 201 /* ClassDeclaration */) {
|
|
if (thisNodeIsDecorated) {
|
|
// To preserve the correct runtime semantics when decorators are applied to the class,
|
|
// the emit needs to follow one of the following rules:
|
|
//
|
|
// * For a local class declaration:
|
|
//
|
|
// @dec class C {
|
|
// }
|
|
//
|
|
// The emit should be:
|
|
//
|
|
// let C = class {
|
|
// };
|
|
// Object.defineProperty(C, "name", { value: "C", configurable: true });
|
|
// C = __decorate([dec], C);
|
|
//
|
|
// * For an exported class declaration:
|
|
//
|
|
// @dec export class C {
|
|
// }
|
|
//
|
|
// The emit should be:
|
|
//
|
|
// export let C = class {
|
|
// };
|
|
// Object.defineProperty(C, "name", { value: "C", configurable: true });
|
|
// C = __decorate([dec], C);
|
|
//
|
|
// * For a default export of a class declaration with a name:
|
|
//
|
|
// @dec default export class C {
|
|
// }
|
|
//
|
|
// The emit should be:
|
|
//
|
|
// let C = class {
|
|
// }
|
|
// Object.defineProperty(C, "name", { value: "C", configurable: true });
|
|
// C = __decorate([dec], C);
|
|
// export default C;
|
|
//
|
|
// * For a default export of a class declaration without a name:
|
|
//
|
|
// @dec default export class {
|
|
// }
|
|
//
|
|
// The emit should be:
|
|
//
|
|
// let _default = class {
|
|
// }
|
|
// _default = __decorate([dec], _default);
|
|
// export default _default;
|
|
//
|
|
if (isES6ExportedDeclaration(node) && !(node.flags & 256 /* Default */)) {
|
|
write("export ");
|
|
}
|
|
write("let ");
|
|
emitDeclarationName(node);
|
|
write(" = ");
|
|
}
|
|
else if (isES6ExportedDeclaration(node)) {
|
|
write("export ");
|
|
if (node.flags & 256 /* Default */) {
|
|
write("default ");
|
|
}
|
|
}
|
|
}
|
|
// If the class has static properties, and it's a class expression, then we'll need
|
|
// to specialize the emit a bit. for a class expression of the form:
|
|
//
|
|
// class C { static a = 1; static b = 2; ... }
|
|
//
|
|
// We'll emit:
|
|
//
|
|
// (_temp = class C { ... }, _temp.a = 1, _temp.b = 2, _temp)
|
|
//
|
|
// This keeps the expression as an expression, while ensuring that the static parts
|
|
// of it have been initialized by the time it is used.
|
|
var staticProperties = getInitializedProperties(node, true);
|
|
var isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === 174 /* ClassExpression */;
|
|
var tempVariable;
|
|
if (isClassExpressionWithStaticProperties) {
|
|
tempVariable = createAndRecordTempVariable(0 /* Auto */);
|
|
write("(");
|
|
increaseIndent();
|
|
emit(tempVariable);
|
|
write(" = ");
|
|
}
|
|
write("class");
|
|
// check if this is an "export default class" as it may not have a name. Do not emit the name if the class is decorated.
|
|
if ((node.name || !(node.flags & 256 /* Default */)) && !thisNodeIsDecorated) {
|
|
write(" ");
|
|
emitDeclarationName(node);
|
|
}
|
|
var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node);
|
|
if (baseTypeNode) {
|
|
write(" extends ");
|
|
emit(baseTypeNode.expression);
|
|
}
|
|
write(" {");
|
|
increaseIndent();
|
|
scopeEmitStart(node);
|
|
writeLine();
|
|
emitConstructor(node, baseTypeNode);
|
|
emitMemberFunctionsForES6AndHigher(node);
|
|
decreaseIndent();
|
|
writeLine();
|
|
emitToken(15 /* CloseBraceToken */, node.members.end);
|
|
scopeEmitEnd();
|
|
// For a decorated class, we need to assign its name (if it has one). This is because we emit
|
|
// the class as a class expression to avoid the double-binding of the identifier:
|
|
//
|
|
// let C = class {
|
|
// }
|
|
// Object.defineProperty(C, "name", { value: "C", configurable: true });
|
|
//
|
|
if (thisNodeIsDecorated) {
|
|
write(";");
|
|
if (node.name) {
|
|
writeLine();
|
|
write("Object.defineProperty(");
|
|
emitDeclarationName(node);
|
|
write(", \"name\", { value: \"");
|
|
emitDeclarationName(node);
|
|
write("\", configurable: true });");
|
|
writeLine();
|
|
}
|
|
}
|
|
// Emit static property assignment. Because classDeclaration is lexically evaluated,
|
|
// it is safe to emit static property assignment after classDeclaration
|
|
// From ES6 specification:
|
|
// HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using
|
|
// a lexical declaration such as a LexicalDeclaration or a ClassDeclaration.
|
|
if (isClassExpressionWithStaticProperties) {
|
|
for (var _i = 0; _i < staticProperties.length; _i++) {
|
|
var property = staticProperties[_i];
|
|
write(",");
|
|
writeLine();
|
|
emitPropertyDeclaration(node, property, tempVariable, true);
|
|
}
|
|
write(",");
|
|
writeLine();
|
|
emit(tempVariable);
|
|
decreaseIndent();
|
|
write(")");
|
|
}
|
|
else {
|
|
writeLine();
|
|
emitPropertyDeclarations(node, staticProperties);
|
|
emitDecoratorsOfClass(node);
|
|
}
|
|
// If this is an exported class, but not on the top level (i.e. on an internal
|
|
// module), export it
|
|
if (!isES6ExportedDeclaration(node) && (node.flags & 1 /* Export */)) {
|
|
writeLine();
|
|
emitStart(node);
|
|
emitModuleMemberName(node);
|
|
write(" = ");
|
|
emitDeclarationName(node);
|
|
emitEnd(node);
|
|
write(";");
|
|
}
|
|
else if (isES6ExportedDeclaration(node) && (node.flags & 256 /* Default */) && thisNodeIsDecorated) {
|
|
// if this is a top level default export of decorated class, write the export after the declaration.
|
|
writeLine();
|
|
write("export default ");
|
|
emitDeclarationName(node);
|
|
write(";");
|
|
}
|
|
}
|
|
function emitClassLikeDeclarationBelowES6(node) {
|
|
if (node.kind === 201 /* ClassDeclaration */) {
|
|
// source file level classes in system modules are hoisted so 'var's for them are already defined
|
|
if (!isSourceFileLevelDeclarationInSystemExternalModule(node, false)) {
|
|
write("var ");
|
|
}
|
|
emitDeclarationName(node);
|
|
write(" = ");
|
|
}
|
|
write("(function (");
|
|
var baseTypeNode = ts.getClassExtendsHeritageClauseElement(node);
|
|
if (baseTypeNode) {
|
|
write("_super");
|
|
}
|
|
write(") {");
|
|
var saveTempFlags = tempFlags;
|
|
var saveTempVariables = tempVariables;
|
|
var saveTempParameters = tempParameters;
|
|
var saveComputedPropertyNamesToGeneratedNames = computedPropertyNamesToGeneratedNames;
|
|
tempFlags = 0;
|
|
tempVariables = undefined;
|
|
tempParameters = undefined;
|
|
computedPropertyNamesToGeneratedNames = undefined;
|
|
increaseIndent();
|
|
scopeEmitStart(node);
|
|
if (baseTypeNode) {
|
|
writeLine();
|
|
emitStart(baseTypeNode);
|
|
write("__extends(");
|
|
emitDeclarationName(node);
|
|
write(", _super);");
|
|
emitEnd(baseTypeNode);
|
|
}
|
|
writeLine();
|
|
emitConstructor(node, baseTypeNode);
|
|
emitMemberFunctionsForES5AndLower(node);
|
|
emitPropertyDeclarations(node, getInitializedProperties(node, true));
|
|
writeLine();
|
|
emitDecoratorsOfClass(node);
|
|
writeLine();
|
|
emitToken(15 /* CloseBraceToken */, node.members.end, function () {
|
|
write("return ");
|
|
emitDeclarationName(node);
|
|
});
|
|
write(";");
|
|
emitTempDeclarations(true);
|
|
tempFlags = saveTempFlags;
|
|
tempVariables = saveTempVariables;
|
|
tempParameters = saveTempParameters;
|
|
computedPropertyNamesToGeneratedNames = saveComputedPropertyNamesToGeneratedNames;
|
|
decreaseIndent();
|
|
writeLine();
|
|
emitToken(15 /* CloseBraceToken */, node.members.end);
|
|
scopeEmitEnd();
|
|
emitStart(node);
|
|
write(")(");
|
|
if (baseTypeNode) {
|
|
emit(baseTypeNode.expression);
|
|
}
|
|
write(")");
|
|
if (node.kind === 201 /* ClassDeclaration */) {
|
|
write(";");
|
|
}
|
|
emitEnd(node);
|
|
if (node.kind === 201 /* ClassDeclaration */) {
|
|
emitExportMemberAssignment(node);
|
|
}
|
|
if (languageVersion < 2 /* ES6 */ && node.parent === currentSourceFile && node.name) {
|
|
emitExportMemberAssignments(node.name);
|
|
}
|
|
}
|
|
function emitClassMemberPrefix(node, member) {
|
|
emitDeclarationName(node);
|
|
if (!(member.flags & 128 /* Static */)) {
|
|
write(".prototype");
|
|
}
|
|
}
|
|
function emitDecoratorsOfClass(node) {
|
|
emitDecoratorsOfMembers(node, 0);
|
|
emitDecoratorsOfMembers(node, 128 /* Static */);
|
|
emitDecoratorsOfConstructor(node);
|
|
}
|
|
function emitDecoratorsOfConstructor(node) {
|
|
var decorators = node.decorators;
|
|
var constructor = ts.getFirstConstructorWithBody(node);
|
|
var hasDecoratedParameters = constructor && ts.forEach(constructor.parameters, ts.nodeIsDecorated);
|
|
// skip decoration of the constructor if neither it nor its parameters are decorated
|
|
if (!decorators && !hasDecoratedParameters) {
|
|
return;
|
|
}
|
|
// Emit the call to __decorate. Given the class:
|
|
//
|
|
// @dec
|
|
// class C {
|
|
// }
|
|
//
|
|
// The emit for the class is:
|
|
//
|
|
// C = __decorate([dec], C);
|
|
//
|
|
writeLine();
|
|
emitStart(node);
|
|
emitDeclarationName(node);
|
|
write(" = __decorate([");
|
|
increaseIndent();
|
|
writeLine();
|
|
var decoratorCount = decorators ? decorators.length : 0;
|
|
var argumentsWritten = emitList(decorators, 0, decoratorCount, true, false, false, true, function (decorator) {
|
|
emitStart(decorator);
|
|
emit(decorator.expression);
|
|
emitEnd(decorator);
|
|
});
|
|
argumentsWritten += emitDecoratorsOfParameters(constructor, argumentsWritten > 0);
|
|
emitSerializedTypeMetadata(node, argumentsWritten >= 0);
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("], ");
|
|
emitDeclarationName(node);
|
|
write(");");
|
|
emitEnd(node);
|
|
writeLine();
|
|
}
|
|
function emitDecoratorsOfMembers(node, staticFlag) {
|
|
for (var _i = 0, _a = node.members; _i < _a.length; _i++) {
|
|
var member = _a[_i];
|
|
// only emit members in the correct group
|
|
if ((member.flags & 128 /* Static */) !== staticFlag) {
|
|
continue;
|
|
}
|
|
// skip members that cannot be decorated (such as the constructor)
|
|
if (!ts.nodeCanBeDecorated(member)) {
|
|
continue;
|
|
}
|
|
// skip a member if it or any of its parameters are not decorated
|
|
if (!ts.nodeOrChildIsDecorated(member)) {
|
|
continue;
|
|
}
|
|
// skip an accessor declaration if it is not the first accessor
|
|
var decorators = void 0;
|
|
var functionLikeMember = void 0;
|
|
if (ts.isAccessor(member)) {
|
|
var accessors = ts.getAllAccessorDeclarations(node.members, member);
|
|
if (member !== accessors.firstAccessor) {
|
|
continue;
|
|
}
|
|
// get the decorators from the first accessor with decorators
|
|
decorators = accessors.firstAccessor.decorators;
|
|
if (!decorators && accessors.secondAccessor) {
|
|
decorators = accessors.secondAccessor.decorators;
|
|
}
|
|
// we only decorate parameters of the set accessor
|
|
functionLikeMember = accessors.setAccessor;
|
|
}
|
|
else {
|
|
decorators = member.decorators;
|
|
// we only decorate the parameters here if this is a method
|
|
if (member.kind === 134 /* MethodDeclaration */) {
|
|
functionLikeMember = member;
|
|
}
|
|
}
|
|
// Emit the call to __decorate. Given the following:
|
|
//
|
|
// class C {
|
|
// @dec method(@dec2 x) {}
|
|
// @dec get accessor() {}
|
|
// @dec prop;
|
|
// }
|
|
//
|
|
// The emit for a method is:
|
|
//
|
|
// Object.defineProperty(C.prototype, "method",
|
|
// __decorate([
|
|
// dec,
|
|
// __param(0, dec2),
|
|
// __metadata("design:type", Function),
|
|
// __metadata("design:paramtypes", [Object]),
|
|
// __metadata("design:returntype", void 0)
|
|
// ], C.prototype, "method", Object.getOwnPropertyDescriptor(C.prototype, "method")));
|
|
//
|
|
// The emit for an accessor is:
|
|
//
|
|
// Object.defineProperty(C.prototype, "accessor",
|
|
// __decorate([
|
|
// dec
|
|
// ], C.prototype, "accessor", Object.getOwnPropertyDescriptor(C.prototype, "accessor")));
|
|
//
|
|
// The emit for a property is:
|
|
//
|
|
// __decorate([
|
|
// dec
|
|
// ], C.prototype, "prop");
|
|
//
|
|
writeLine();
|
|
emitStart(member);
|
|
if (member.kind !== 132 /* PropertyDeclaration */) {
|
|
write("Object.defineProperty(");
|
|
emitStart(member.name);
|
|
emitClassMemberPrefix(node, member);
|
|
write(", ");
|
|
emitExpressionForPropertyName(member.name);
|
|
emitEnd(member.name);
|
|
write(",");
|
|
increaseIndent();
|
|
writeLine();
|
|
}
|
|
write("__decorate([");
|
|
increaseIndent();
|
|
writeLine();
|
|
var decoratorCount = decorators ? decorators.length : 0;
|
|
var argumentsWritten = emitList(decorators, 0, decoratorCount, true, false, false, true, function (decorator) {
|
|
emitStart(decorator);
|
|
emit(decorator.expression);
|
|
emitEnd(decorator);
|
|
});
|
|
argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0);
|
|
emitSerializedTypeMetadata(member, argumentsWritten > 0);
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("], ");
|
|
emitStart(member.name);
|
|
emitClassMemberPrefix(node, member);
|
|
write(", ");
|
|
emitExpressionForPropertyName(member.name);
|
|
emitEnd(member.name);
|
|
if (member.kind !== 132 /* PropertyDeclaration */) {
|
|
write(", Object.getOwnPropertyDescriptor(");
|
|
emitStart(member.name);
|
|
emitClassMemberPrefix(node, member);
|
|
write(", ");
|
|
emitExpressionForPropertyName(member.name);
|
|
emitEnd(member.name);
|
|
write("))");
|
|
decreaseIndent();
|
|
}
|
|
write(");");
|
|
emitEnd(member);
|
|
writeLine();
|
|
}
|
|
}
|
|
function emitDecoratorsOfParameters(node, leadingComma) {
|
|
var argumentsWritten = 0;
|
|
if (node) {
|
|
var parameterIndex = 0;
|
|
for (var _i = 0, _a = node.parameters; _i < _a.length; _i++) {
|
|
var parameter = _a[_i];
|
|
if (ts.nodeIsDecorated(parameter)) {
|
|
var decorators = parameter.decorators;
|
|
argumentsWritten += emitList(decorators, 0, decorators.length, true, false, leadingComma, true, function (decorator) {
|
|
emitStart(decorator);
|
|
write("__param(" + parameterIndex + ", ");
|
|
emit(decorator.expression);
|
|
write(")");
|
|
emitEnd(decorator);
|
|
});
|
|
leadingComma = true;
|
|
}
|
|
++parameterIndex;
|
|
}
|
|
}
|
|
return argumentsWritten;
|
|
}
|
|
function shouldEmitTypeMetadata(node) {
|
|
// This method determines whether to emit the "design:type" metadata based on the node's kind.
|
|
// The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
|
// compiler option is set.
|
|
switch (node.kind) {
|
|
case 134 /* MethodDeclaration */:
|
|
case 136 /* GetAccessor */:
|
|
case 137 /* SetAccessor */:
|
|
case 132 /* PropertyDeclaration */:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function shouldEmitReturnTypeMetadata(node) {
|
|
// This method determines whether to emit the "design:returntype" metadata based on the node's kind.
|
|
// The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
|
// compiler option is set.
|
|
switch (node.kind) {
|
|
case 134 /* MethodDeclaration */:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function shouldEmitParamTypesMetadata(node) {
|
|
// This method determines whether to emit the "design:paramtypes" metadata based on the node's kind.
|
|
// The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata
|
|
// compiler option is set.
|
|
switch (node.kind) {
|
|
case 201 /* ClassDeclaration */:
|
|
case 134 /* MethodDeclaration */:
|
|
case 137 /* SetAccessor */:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function emitSerializedTypeMetadata(node, writeComma) {
|
|
// This method emits the serialized type metadata for a decorator target.
|
|
// The caller should have already tested whether the node has decorators.
|
|
var argumentsWritten = 0;
|
|
if (compilerOptions.emitDecoratorMetadata) {
|
|
if (shouldEmitTypeMetadata(node)) {
|
|
var serializedType = resolver.serializeTypeOfNode(node, getGeneratedNameForNode);
|
|
if (serializedType) {
|
|
if (writeComma) {
|
|
write(", ");
|
|
}
|
|
writeLine();
|
|
write("__metadata('design:type', ");
|
|
emitSerializedType(node, serializedType);
|
|
write(")");
|
|
argumentsWritten++;
|
|
}
|
|
}
|
|
if (shouldEmitParamTypesMetadata(node)) {
|
|
var serializedTypes = resolver.serializeParameterTypesOfNode(node, getGeneratedNameForNode);
|
|
if (serializedTypes) {
|
|
if (writeComma || argumentsWritten) {
|
|
write(", ");
|
|
}
|
|
writeLine();
|
|
write("__metadata('design:paramtypes', [");
|
|
for (var i = 0; i < serializedTypes.length; ++i) {
|
|
if (i > 0) {
|
|
write(", ");
|
|
}
|
|
emitSerializedType(node, serializedTypes[i]);
|
|
}
|
|
write("])");
|
|
argumentsWritten++;
|
|
}
|
|
}
|
|
if (shouldEmitReturnTypeMetadata(node)) {
|
|
var serializedType = resolver.serializeReturnTypeOfNode(node, getGeneratedNameForNode);
|
|
if (serializedType) {
|
|
if (writeComma || argumentsWritten) {
|
|
write(", ");
|
|
}
|
|
writeLine();
|
|
write("__metadata('design:returntype', ");
|
|
emitSerializedType(node, serializedType);
|
|
write(")");
|
|
argumentsWritten++;
|
|
}
|
|
}
|
|
}
|
|
return argumentsWritten;
|
|
}
|
|
function serializeTypeNameSegment(location, path, index) {
|
|
switch (index) {
|
|
case 0:
|
|
return "typeof " + path[index] + " !== 'undefined' && " + path[index];
|
|
case 1:
|
|
return serializeTypeNameSegment(location, path, index - 1) + "." + path[index];
|
|
default:
|
|
var temp = createAndRecordTempVariable(0 /* Auto */).text;
|
|
return "(" + temp + " = " + serializeTypeNameSegment(location, path, index - 1) + ") && " + temp + "." + path[index];
|
|
}
|
|
}
|
|
function emitSerializedType(location, name) {
|
|
if (typeof name === "string") {
|
|
write(name);
|
|
return;
|
|
}
|
|
else {
|
|
ts.Debug.assert(name.length > 0, "Invalid serialized type name");
|
|
write("(" + serializeTypeNameSegment(location, name, name.length - 1) + ") || Object");
|
|
}
|
|
}
|
|
function emitInterfaceDeclaration(node) {
|
|
emitOnlyPinnedOrTripleSlashComments(node);
|
|
}
|
|
function shouldEmitEnumDeclaration(node) {
|
|
var isConstEnum = ts.isConst(node);
|
|
return !isConstEnum || compilerOptions.preserveConstEnums || compilerOptions.separateCompilation;
|
|
}
|
|
function emitEnumDeclaration(node) {
|
|
// const enums are completely erased during compilation.
|
|
if (!shouldEmitEnumDeclaration(node)) {
|
|
return;
|
|
}
|
|
if (!(node.flags & 1 /* Export */) || isES6ExportedDeclaration(node)) {
|
|
emitStart(node);
|
|
if (isES6ExportedDeclaration(node)) {
|
|
write("export ");
|
|
}
|
|
write("var ");
|
|
emit(node.name);
|
|
emitEnd(node);
|
|
write(";");
|
|
}
|
|
writeLine();
|
|
emitStart(node);
|
|
write("(function (");
|
|
emitStart(node.name);
|
|
write(getGeneratedNameForNode(node));
|
|
emitEnd(node.name);
|
|
write(") {");
|
|
increaseIndent();
|
|
scopeEmitStart(node);
|
|
emitLines(node.members);
|
|
decreaseIndent();
|
|
writeLine();
|
|
emitToken(15 /* CloseBraceToken */, node.members.end);
|
|
scopeEmitEnd();
|
|
write(")(");
|
|
emitModuleMemberName(node);
|
|
write(" || (");
|
|
emitModuleMemberName(node);
|
|
write(" = {}));");
|
|
emitEnd(node);
|
|
if (!isES6ExportedDeclaration(node) && node.flags & 1 /* Export */) {
|
|
writeLine();
|
|
emitStart(node);
|
|
write("var ");
|
|
emit(node.name);
|
|
write(" = ");
|
|
emitModuleMemberName(node);
|
|
emitEnd(node);
|
|
write(";");
|
|
}
|
|
if (languageVersion < 2 /* ES6 */ && node.parent === currentSourceFile) {
|
|
emitExportMemberAssignments(node.name);
|
|
}
|
|
}
|
|
function emitEnumMember(node) {
|
|
var enumParent = node.parent;
|
|
emitStart(node);
|
|
write(getGeneratedNameForNode(enumParent));
|
|
write("[");
|
|
write(getGeneratedNameForNode(enumParent));
|
|
write("[");
|
|
emitExpressionForPropertyName(node.name);
|
|
write("] = ");
|
|
writeEnumMemberDeclarationValue(node);
|
|
write("] = ");
|
|
emitExpressionForPropertyName(node.name);
|
|
emitEnd(node);
|
|
write(";");
|
|
}
|
|
function writeEnumMemberDeclarationValue(member) {
|
|
var value = resolver.getConstantValue(member);
|
|
if (value !== undefined) {
|
|
write(value.toString());
|
|
return;
|
|
}
|
|
else if (member.initializer) {
|
|
emit(member.initializer);
|
|
}
|
|
else {
|
|
write("undefined");
|
|
}
|
|
}
|
|
function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration) {
|
|
if (moduleDeclaration.body.kind === 205 /* ModuleDeclaration */) {
|
|
var recursiveInnerModule = getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration.body);
|
|
return recursiveInnerModule || moduleDeclaration.body;
|
|
}
|
|
}
|
|
function shouldEmitModuleDeclaration(node) {
|
|
return ts.isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation);
|
|
}
|
|
function isModuleMergedWithES6Class(node) {
|
|
return languageVersion === 2 /* ES6 */ && !!(resolver.getNodeCheckFlags(node) & 2048 /* LexicalModuleMergesWithClass */);
|
|
}
|
|
function emitModuleDeclaration(node) {
|
|
// Emit only if this module is non-ambient.
|
|
var shouldEmit = shouldEmitModuleDeclaration(node);
|
|
if (!shouldEmit) {
|
|
return emitOnlyPinnedOrTripleSlashComments(node);
|
|
}
|
|
var hoistedInDeclarationScope = isSourceFileLevelDeclarationInSystemExternalModule(node, false);
|
|
var emitVarForModule = !hoistedInDeclarationScope && !isModuleMergedWithES6Class(node);
|
|
if (emitVarForModule) {
|
|
emitStart(node);
|
|
if (isES6ExportedDeclaration(node)) {
|
|
write("export ");
|
|
}
|
|
write("var ");
|
|
emit(node.name);
|
|
write(";");
|
|
emitEnd(node);
|
|
writeLine();
|
|
}
|
|
emitStart(node);
|
|
write("(function (");
|
|
emitStart(node.name);
|
|
write(getGeneratedNameForNode(node));
|
|
emitEnd(node.name);
|
|
write(") ");
|
|
if (node.body.kind === 206 /* ModuleBlock */) {
|
|
var saveTempFlags = tempFlags;
|
|
var saveTempVariables = tempVariables;
|
|
tempFlags = 0;
|
|
tempVariables = undefined;
|
|
emit(node.body);
|
|
tempFlags = saveTempFlags;
|
|
tempVariables = saveTempVariables;
|
|
}
|
|
else {
|
|
write("{");
|
|
increaseIndent();
|
|
scopeEmitStart(node);
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
writeLine();
|
|
emit(node.body);
|
|
decreaseIndent();
|
|
writeLine();
|
|
var moduleBlock = getInnerMostModuleDeclarationFromDottedModule(node).body;
|
|
emitToken(15 /* CloseBraceToken */, moduleBlock.statements.end);
|
|
scopeEmitEnd();
|
|
}
|
|
write(")(");
|
|
// write moduleDecl = containingModule.m only if it is not exported es6 module member
|
|
if ((node.flags & 1 /* Export */) && !isES6ExportedDeclaration(node)) {
|
|
emit(node.name);
|
|
write(" = ");
|
|
}
|
|
emitModuleMemberName(node);
|
|
write(" || (");
|
|
emitModuleMemberName(node);
|
|
write(" = {}));");
|
|
emitEnd(node);
|
|
if (!isES6ExportedDeclaration(node) && node.name.kind === 65 /* Identifier */ && node.parent === currentSourceFile) {
|
|
if (compilerOptions.module === 3 /* System */ && (node.flags & 1 /* Export */)) {
|
|
writeLine();
|
|
write(exportFunctionForFile + "(\"");
|
|
emitDeclarationName(node);
|
|
write("\", ");
|
|
emitDeclarationName(node);
|
|
write(")");
|
|
}
|
|
emitExportMemberAssignments(node.name);
|
|
}
|
|
}
|
|
function emitRequire(moduleName) {
|
|
if (moduleName.kind === 8 /* StringLiteral */) {
|
|
write("require(");
|
|
emitStart(moduleName);
|
|
emitLiteral(moduleName);
|
|
emitEnd(moduleName);
|
|
emitToken(17 /* CloseParenToken */, moduleName.end);
|
|
}
|
|
else {
|
|
write("require()");
|
|
}
|
|
}
|
|
function getNamespaceDeclarationNode(node) {
|
|
if (node.kind === 208 /* ImportEqualsDeclaration */) {
|
|
return node;
|
|
}
|
|
var importClause = node.importClause;
|
|
if (importClause && importClause.namedBindings && importClause.namedBindings.kind === 211 /* NamespaceImport */) {
|
|
return importClause.namedBindings;
|
|
}
|
|
}
|
|
function isDefaultImport(node) {
|
|
return node.kind === 209 /* ImportDeclaration */ && node.importClause && !!node.importClause.name;
|
|
}
|
|
function emitExportImportAssignments(node) {
|
|
if (ts.isAliasSymbolDeclaration(node) && resolver.isValueAliasDeclaration(node)) {
|
|
emitExportMemberAssignments(node.name);
|
|
}
|
|
ts.forEachChild(node, emitExportImportAssignments);
|
|
}
|
|
function emitImportDeclaration(node) {
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
return emitExternalImportDeclaration(node);
|
|
}
|
|
// ES6 import
|
|
if (node.importClause) {
|
|
var shouldEmitDefaultBindings = resolver.isReferencedAliasDeclaration(node.importClause);
|
|
var shouldEmitNamedBindings = node.importClause.namedBindings && resolver.isReferencedAliasDeclaration(node.importClause.namedBindings, true);
|
|
if (shouldEmitDefaultBindings || shouldEmitNamedBindings) {
|
|
write("import ");
|
|
emitStart(node.importClause);
|
|
if (shouldEmitDefaultBindings) {
|
|
emit(node.importClause.name);
|
|
if (shouldEmitNamedBindings) {
|
|
write(", ");
|
|
}
|
|
}
|
|
if (shouldEmitNamedBindings) {
|
|
emitLeadingComments(node.importClause.namedBindings);
|
|
emitStart(node.importClause.namedBindings);
|
|
if (node.importClause.namedBindings.kind === 211 /* NamespaceImport */) {
|
|
write("* as ");
|
|
emit(node.importClause.namedBindings.name);
|
|
}
|
|
else {
|
|
write("{ ");
|
|
emitExportOrImportSpecifierList(node.importClause.namedBindings.elements, resolver.isReferencedAliasDeclaration);
|
|
write(" }");
|
|
}
|
|
emitEnd(node.importClause.namedBindings);
|
|
emitTrailingComments(node.importClause.namedBindings);
|
|
}
|
|
emitEnd(node.importClause);
|
|
write(" from ");
|
|
emit(node.moduleSpecifier);
|
|
write(";");
|
|
}
|
|
}
|
|
else {
|
|
write("import ");
|
|
emit(node.moduleSpecifier);
|
|
write(";");
|
|
}
|
|
}
|
|
function emitExternalImportDeclaration(node) {
|
|
if (ts.contains(externalImports, node)) {
|
|
var isExportedImport = node.kind === 208 /* ImportEqualsDeclaration */ && (node.flags & 1 /* Export */) !== 0;
|
|
var namespaceDeclaration = getNamespaceDeclarationNode(node);
|
|
if (compilerOptions.module !== 2 /* AMD */) {
|
|
emitLeadingComments(node);
|
|
emitStart(node);
|
|
if (namespaceDeclaration && !isDefaultImport(node)) {
|
|
// import x = require("foo")
|
|
// import * as x from "foo"
|
|
if (!isExportedImport)
|
|
write("var ");
|
|
emitModuleMemberName(namespaceDeclaration);
|
|
write(" = ");
|
|
}
|
|
else {
|
|
// import "foo"
|
|
// import x from "foo"
|
|
// import { x, y } from "foo"
|
|
// import d, * as x from "foo"
|
|
// import d, { x, y } from "foo"
|
|
var isNakedImport = 209 /* ImportDeclaration */ && !node.importClause;
|
|
if (!isNakedImport) {
|
|
write("var ");
|
|
write(getGeneratedNameForNode(node));
|
|
write(" = ");
|
|
}
|
|
}
|
|
emitRequire(ts.getExternalModuleName(node));
|
|
if (namespaceDeclaration && isDefaultImport(node)) {
|
|
// import d, * as x from "foo"
|
|
write(", ");
|
|
emitModuleMemberName(namespaceDeclaration);
|
|
write(" = ");
|
|
write(getGeneratedNameForNode(node));
|
|
}
|
|
write(";");
|
|
emitEnd(node);
|
|
emitExportImportAssignments(node);
|
|
emitTrailingComments(node);
|
|
}
|
|
else {
|
|
if (isExportedImport) {
|
|
emitModuleMemberName(namespaceDeclaration);
|
|
write(" = ");
|
|
emit(namespaceDeclaration.name);
|
|
write(";");
|
|
}
|
|
else if (namespaceDeclaration && isDefaultImport(node)) {
|
|
// import d, * as x from "foo"
|
|
write("var ");
|
|
emitModuleMemberName(namespaceDeclaration);
|
|
write(" = ");
|
|
write(getGeneratedNameForNode(node));
|
|
write(";");
|
|
}
|
|
emitExportImportAssignments(node);
|
|
}
|
|
}
|
|
}
|
|
function emitImportEqualsDeclaration(node) {
|
|
if (ts.isExternalModuleImportEqualsDeclaration(node)) {
|
|
emitExternalImportDeclaration(node);
|
|
return;
|
|
}
|
|
// preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when
|
|
// - current file is not external module
|
|
// - import declaration is top level and target is value imported by entity name
|
|
if (resolver.isReferencedAliasDeclaration(node) ||
|
|
(!ts.isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportEqualsWithEntityName(node))) {
|
|
emitLeadingComments(node);
|
|
emitStart(node);
|
|
if (isES6ExportedDeclaration(node)) {
|
|
write("export ");
|
|
write("var ");
|
|
}
|
|
else if (!(node.flags & 1 /* Export */)) {
|
|
write("var ");
|
|
}
|
|
emitModuleMemberName(node);
|
|
write(" = ");
|
|
emit(node.moduleReference);
|
|
write(";");
|
|
emitEnd(node);
|
|
emitExportImportAssignments(node);
|
|
emitTrailingComments(node);
|
|
}
|
|
}
|
|
function emitExportDeclaration(node) {
|
|
ts.Debug.assert(compilerOptions.module !== 3 /* System */);
|
|
if (languageVersion < 2 /* ES6 */) {
|
|
if (node.moduleSpecifier && (!node.exportClause || resolver.isValueAliasDeclaration(node))) {
|
|
emitStart(node);
|
|
var generatedName = getGeneratedNameForNode(node);
|
|
if (node.exportClause) {
|
|
// export { x, y, ... } from "foo"
|
|
if (compilerOptions.module !== 2 /* AMD */) {
|
|
write("var ");
|
|
write(generatedName);
|
|
write(" = ");
|
|
emitRequire(ts.getExternalModuleName(node));
|
|
write(";");
|
|
}
|
|
for (var _i = 0, _a = node.exportClause.elements; _i < _a.length; _i++) {
|
|
var specifier = _a[_i];
|
|
if (resolver.isValueAliasDeclaration(specifier)) {
|
|
writeLine();
|
|
emitStart(specifier);
|
|
emitContainingModuleName(specifier);
|
|
write(".");
|
|
emitNodeWithoutSourceMap(specifier.name);
|
|
write(" = ");
|
|
write(generatedName);
|
|
write(".");
|
|
emitNodeWithoutSourceMap(specifier.propertyName || specifier.name);
|
|
write(";");
|
|
emitEnd(specifier);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// export * from "foo"
|
|
writeLine();
|
|
write("__export(");
|
|
if (compilerOptions.module !== 2 /* AMD */) {
|
|
emitRequire(ts.getExternalModuleName(node));
|
|
}
|
|
else {
|
|
write(generatedName);
|
|
}
|
|
write(");");
|
|
}
|
|
emitEnd(node);
|
|
}
|
|
}
|
|
else {
|
|
if (!node.exportClause || resolver.isValueAliasDeclaration(node)) {
|
|
emitStart(node);
|
|
write("export ");
|
|
if (node.exportClause) {
|
|
// export { x, y, ... }
|
|
write("{ ");
|
|
emitExportOrImportSpecifierList(node.exportClause.elements, resolver.isValueAliasDeclaration);
|
|
write(" }");
|
|
}
|
|
else {
|
|
write("*");
|
|
}
|
|
if (node.moduleSpecifier) {
|
|
write(" from ");
|
|
emitNodeWithoutSourceMap(node.moduleSpecifier);
|
|
}
|
|
write(";");
|
|
emitEnd(node);
|
|
}
|
|
}
|
|
}
|
|
function emitExportOrImportSpecifierList(specifiers, shouldEmit) {
|
|
ts.Debug.assert(languageVersion >= 2 /* ES6 */);
|
|
var needsComma = false;
|
|
for (var _i = 0; _i < specifiers.length; _i++) {
|
|
var specifier = specifiers[_i];
|
|
if (shouldEmit(specifier)) {
|
|
if (needsComma) {
|
|
write(", ");
|
|
}
|
|
emitStart(specifier);
|
|
if (specifier.propertyName) {
|
|
emitNodeWithoutSourceMap(specifier.propertyName);
|
|
write(" as ");
|
|
}
|
|
emitNodeWithoutSourceMap(specifier.name);
|
|
emitEnd(specifier);
|
|
needsComma = true;
|
|
}
|
|
}
|
|
}
|
|
function emitExportAssignment(node) {
|
|
if (!node.isExportEquals && resolver.isValueAliasDeclaration(node)) {
|
|
if (languageVersion >= 2 /* ES6 */) {
|
|
writeLine();
|
|
emitStart(node);
|
|
write("export default ");
|
|
var expression = node.expression;
|
|
emit(expression);
|
|
if (expression.kind !== 200 /* FunctionDeclaration */ &&
|
|
expression.kind !== 201 /* ClassDeclaration */) {
|
|
write(";");
|
|
}
|
|
emitEnd(node);
|
|
}
|
|
else {
|
|
writeLine();
|
|
emitStart(node);
|
|
if (compilerOptions.module === 3 /* System */) {
|
|
write(exportFunctionForFile + "(\"default\",");
|
|
emit(node.expression);
|
|
write(")");
|
|
}
|
|
else {
|
|
emitContainingModuleName(node);
|
|
if (languageVersion === 0 /* ES3 */) {
|
|
write("[\"default\"] = ");
|
|
}
|
|
else {
|
|
write(".default = ");
|
|
}
|
|
emit(node.expression);
|
|
}
|
|
write(";");
|
|
emitEnd(node);
|
|
}
|
|
}
|
|
}
|
|
function collectExternalModuleInfo(sourceFile) {
|
|
externalImports = [];
|
|
exportSpecifiers = {};
|
|
exportEquals = undefined;
|
|
hasExportStars = false;
|
|
for (var _i = 0, _a = sourceFile.statements; _i < _a.length; _i++) {
|
|
var node = _a[_i];
|
|
switch (node.kind) {
|
|
case 209 /* ImportDeclaration */:
|
|
if (!node.importClause ||
|
|
resolver.isReferencedAliasDeclaration(node.importClause, true)) {
|
|
// import "mod"
|
|
// import x from "mod" where x is referenced
|
|
// import * as x from "mod" where x is referenced
|
|
// import { x, y } from "mod" where at least one import is referenced
|
|
externalImports.push(node);
|
|
}
|
|
break;
|
|
case 208 /* ImportEqualsDeclaration */:
|
|
if (node.moduleReference.kind === 219 /* ExternalModuleReference */ && resolver.isReferencedAliasDeclaration(node)) {
|
|
// import x = require("mod") where x is referenced
|
|
externalImports.push(node);
|
|
}
|
|
break;
|
|
case 215 /* ExportDeclaration */:
|
|
if (node.moduleSpecifier) {
|
|
if (!node.exportClause) {
|
|
// export * from "mod"
|
|
externalImports.push(node);
|
|
hasExportStars = true;
|
|
}
|
|
else if (resolver.isValueAliasDeclaration(node)) {
|
|
// export { x, y } from "mod" where at least one export is a value symbol
|
|
externalImports.push(node);
|
|
}
|
|
}
|
|
else {
|
|
// export { x, y }
|
|
for (var _b = 0, _c = node.exportClause.elements; _b < _c.length; _b++) {
|
|
var specifier = _c[_b];
|
|
var name_6 = (specifier.propertyName || specifier.name).text;
|
|
(exportSpecifiers[name_6] || (exportSpecifiers[name_6] = [])).push(specifier);
|
|
}
|
|
}
|
|
break;
|
|
case 214 /* ExportAssignment */:
|
|
if (node.isExportEquals && !exportEquals) {
|
|
// export = x
|
|
exportEquals = node;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
function emitExportStarHelper() {
|
|
if (hasExportStars) {
|
|
writeLine();
|
|
write("function __export(m) {");
|
|
increaseIndent();
|
|
writeLine();
|
|
write("for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];");
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("}");
|
|
}
|
|
}
|
|
function getLocalNameForExternalImport(importNode) {
|
|
var namespaceDeclaration = getNamespaceDeclarationNode(importNode);
|
|
if (namespaceDeclaration && !isDefaultImport(importNode)) {
|
|
return ts.getSourceTextOfNodeFromSourceFile(currentSourceFile, namespaceDeclaration.name);
|
|
}
|
|
else {
|
|
return getGeneratedNameForNode(importNode);
|
|
}
|
|
}
|
|
function getExternalModuleNameText(importNode) {
|
|
var moduleName = ts.getExternalModuleName(importNode);
|
|
if (moduleName.kind === 8 /* StringLiteral */) {
|
|
return getLiteralText(moduleName);
|
|
}
|
|
return undefined;
|
|
}
|
|
function emitVariableDeclarationsForImports() {
|
|
if (externalImports.length === 0) {
|
|
return;
|
|
}
|
|
writeLine();
|
|
var started = false;
|
|
for (var _i = 0; _i < externalImports.length; _i++) {
|
|
var importNode = externalImports[_i];
|
|
// do not create variable declaration for exports and imports that lack import clause
|
|
var skipNode = importNode.kind === 215 /* ExportDeclaration */ ||
|
|
(importNode.kind === 209 /* ImportDeclaration */ && !importNode.importClause);
|
|
if (skipNode) {
|
|
continue;
|
|
}
|
|
if (!started) {
|
|
write("var ");
|
|
started = true;
|
|
}
|
|
else {
|
|
write(", ");
|
|
}
|
|
write(getLocalNameForExternalImport(importNode));
|
|
}
|
|
if (started) {
|
|
write(";");
|
|
}
|
|
}
|
|
function hoistTopLevelVariableAndFunctionDeclarations(node) {
|
|
// per ES6 spec:
|
|
// 15.2.1.16.4 ModuleDeclarationInstantiation() Concrete Method
|
|
// - var declarations are initialized to undefined - 14.a.ii
|
|
// - function/generator declarations are instantiated - 16.a.iv
|
|
// this means that after module is instantiated but before its evaluation
|
|
// exported functions are already accessible at import sites
|
|
// in theory we should hoist only exported functions and its dependencies
|
|
// in practice to simplify things we'll hoist all source level functions and variable declaration
|
|
// including variables declarations for module and class declarations
|
|
var hoistedVars;
|
|
var hoistedFunctionDeclarations;
|
|
visit(node);
|
|
if (hoistedVars) {
|
|
writeLine();
|
|
write("var ");
|
|
for (var i = 0; i < hoistedVars.length; ++i) {
|
|
var local = hoistedVars[i];
|
|
if (i !== 0) {
|
|
write(", ");
|
|
}
|
|
if (local.kind === 201 /* ClassDeclaration */ || local.kind === 205 /* ModuleDeclaration */) {
|
|
emitDeclarationName(local);
|
|
}
|
|
else {
|
|
emit(local);
|
|
}
|
|
}
|
|
write(";");
|
|
}
|
|
if (hoistedFunctionDeclarations) {
|
|
for (var _i = 0; _i < hoistedFunctionDeclarations.length; _i++) {
|
|
var f = hoistedFunctionDeclarations[_i];
|
|
writeLine();
|
|
emit(f);
|
|
}
|
|
}
|
|
function visit(node) {
|
|
if (node.kind === 200 /* FunctionDeclaration */) {
|
|
if (!hoistedFunctionDeclarations) {
|
|
hoistedFunctionDeclarations = [];
|
|
}
|
|
hoistedFunctionDeclarations.push(node);
|
|
return;
|
|
}
|
|
if (node.kind === 201 /* ClassDeclaration */) {
|
|
// TODO: rename block scoped classes
|
|
if (!hoistedVars) {
|
|
hoistedVars = [];
|
|
}
|
|
hoistedVars.push(node);
|
|
return;
|
|
}
|
|
if (node.kind === 205 /* ModuleDeclaration */ && shouldEmitModuleDeclaration(node)) {
|
|
if (!hoistedVars) {
|
|
hoistedVars = [];
|
|
}
|
|
hoistedVars.push(node);
|
|
return;
|
|
}
|
|
if (node.kind === 198 /* VariableDeclaration */ || node.kind === 152 /* BindingElement */) {
|
|
if (shouldHoistVariable(node, false)) {
|
|
var name_7 = node.name;
|
|
if (name_7.kind === 65 /* Identifier */) {
|
|
if (!hoistedVars) {
|
|
hoistedVars = [];
|
|
}
|
|
hoistedVars.push(name_7);
|
|
}
|
|
else {
|
|
ts.forEachChild(name_7, visit);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (ts.isBindingPattern(node)) {
|
|
ts.forEach(node.elements, visit);
|
|
return;
|
|
}
|
|
if (!ts.isDeclaration(node)) {
|
|
ts.forEachChild(node, visit);
|
|
}
|
|
}
|
|
}
|
|
function shouldHoistVariable(node, checkIfSourceFileLevelDecl) {
|
|
if (checkIfSourceFileLevelDecl && !isSourceFileLevelDeclarationInSystemExternalModule(node, false)) {
|
|
return false;
|
|
}
|
|
// hoist variable if
|
|
// - it is not block scoped
|
|
// - it is top level block scoped
|
|
// if block scoped variables are nested in some another block then
|
|
// no other functions can use them except ones that are defined at least in the same block
|
|
return (ts.getCombinedNodeFlags(node) & 12288 /* BlockScoped */) === 0 ||
|
|
ts.getEnclosingBlockScopeContainer(node).kind === 227 /* SourceFile */;
|
|
}
|
|
function isCurrentFileSystemExternalModule() {
|
|
return compilerOptions.module === 3 /* System */ && ts.isExternalModule(currentSourceFile);
|
|
}
|
|
function emitSystemModuleBody(node, startIndex) {
|
|
// shape of the body in system modules:
|
|
// function (exports) {
|
|
// <list of local aliases for imports>
|
|
// <hoisted function declarations>
|
|
// <hoisted variable declarations>
|
|
// return {
|
|
// setters: [
|
|
// <list of setter function for imports>
|
|
// ],
|
|
// execute: function() {
|
|
// <module statements>
|
|
// }
|
|
// }
|
|
// <temp declarations>
|
|
// }
|
|
// I.e:
|
|
// import {x} from 'file1'
|
|
// var y = 1;
|
|
// export function foo() { return y + x(); }
|
|
// console.log(y);
|
|
// will be transformed to
|
|
// function(exports) {
|
|
// var file1; // local alias
|
|
// var y;
|
|
// function foo() { return y + file1.x(); }
|
|
// exports("foo", foo);
|
|
// return {
|
|
// setters: [
|
|
// function(v) { file1 = v }
|
|
// ],
|
|
// execute(): function() {
|
|
// y = 1;
|
|
// console.log(y);
|
|
// }
|
|
// };
|
|
// }
|
|
emitVariableDeclarationsForImports();
|
|
writeLine();
|
|
hoistTopLevelVariableAndFunctionDeclarations(node);
|
|
writeLine();
|
|
write("return {");
|
|
increaseIndent();
|
|
writeLine();
|
|
emitSetters();
|
|
writeLine();
|
|
emitExecute(node, startIndex);
|
|
emitTempDeclarations(true);
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("}"); // return
|
|
}
|
|
function emitSetters() {
|
|
write("setters:[");
|
|
for (var i = 0; i < externalImports.length; ++i) {
|
|
if (i !== 0) {
|
|
write(",");
|
|
}
|
|
writeLine();
|
|
increaseIndent();
|
|
var importNode = externalImports[i];
|
|
var importVariableName = getLocalNameForExternalImport(importNode) || "";
|
|
var parameterName = "_" + importVariableName;
|
|
write("function (" + parameterName + ") {");
|
|
switch (importNode.kind) {
|
|
case 209 /* ImportDeclaration */:
|
|
if (!importNode.importClause) {
|
|
// 'import "..."' case
|
|
// module is imported only for side-effects, setter body will be empty
|
|
break;
|
|
}
|
|
// fall-through
|
|
case 208 /* ImportEqualsDeclaration */:
|
|
ts.Debug.assert(importVariableName !== "");
|
|
increaseIndent();
|
|
writeLine();
|
|
// save import into the local
|
|
write(importVariableName + " = " + parameterName);
|
|
writeLine();
|
|
var defaultName = importNode.kind === 209 /* ImportDeclaration */
|
|
? importNode.importClause.name
|
|
: importNode.name;
|
|
if (defaultName) {
|
|
// emit re-export for imported default name
|
|
// import n1 from 'foo1'
|
|
// import n2 = require('foo2')
|
|
// export {n1}
|
|
// export {n2}
|
|
emitExportMemberAssignments(defaultName);
|
|
writeLine();
|
|
}
|
|
if (importNode.kind === 209 /* ImportDeclaration */ &&
|
|
importNode.importClause.namedBindings) {
|
|
var namedBindings = importNode.importClause.namedBindings;
|
|
if (namedBindings.kind === 211 /* NamespaceImport */) {
|
|
// emit re-export for namespace
|
|
// import * as n from 'foo'
|
|
// export {n}
|
|
emitExportMemberAssignments(namedBindings.name);
|
|
writeLine();
|
|
}
|
|
else {
|
|
// emit re-exports for named imports
|
|
// import {a, b} from 'foo'
|
|
// export {a, b as c}
|
|
for (var _i = 0, _a = namedBindings.elements; _i < _a.length; _i++) {
|
|
var element = _a[_i];
|
|
emitExportMemberAssignments(element.name || element.propertyName);
|
|
writeLine();
|
|
}
|
|
}
|
|
}
|
|
decreaseIndent();
|
|
break;
|
|
case 215 /* ExportDeclaration */:
|
|
ts.Debug.assert(importVariableName !== "");
|
|
increaseIndent();
|
|
if (importNode.exportClause) {
|
|
// export {a, b as c} from 'foo'
|
|
// emit as:
|
|
// exports('a', _foo["a"])
|
|
// exports('c', _foo["b"])
|
|
for (var _b = 0, _c = importNode.exportClause.elements; _b < _c.length; _b++) {
|
|
var e = _c[_b];
|
|
writeLine();
|
|
write(exportFunctionForFile + "(\"");
|
|
emitNodeWithoutSourceMap(e.name);
|
|
write("\", " + parameterName + "[\"");
|
|
emitNodeWithoutSourceMap(e.propertyName || e.name);
|
|
write("\"]);");
|
|
}
|
|
}
|
|
else {
|
|
writeLine();
|
|
// export * from 'foo'
|
|
// emit as:
|
|
// for (var n in _foo) exports(n, _foo[n]);
|
|
// NOTE: it is safe to use name 'n' since parameter name always starts with '_'
|
|
write("for (var n in " + parameterName + ") " + exportFunctionForFile + "(n, " + parameterName + "[n]);");
|
|
}
|
|
writeLine();
|
|
decreaseIndent();
|
|
break;
|
|
}
|
|
write("}");
|
|
decreaseIndent();
|
|
}
|
|
write("],");
|
|
}
|
|
function emitExecute(node, startIndex) {
|
|
write("execute: function() {");
|
|
increaseIndent();
|
|
writeLine();
|
|
for (var i = startIndex; i < node.statements.length; ++i) {
|
|
var statement = node.statements[i];
|
|
// - imports/exports are not emitted for system modules
|
|
// - function declarations are not emitted because they were already hoisted
|
|
switch (statement.kind) {
|
|
case 215 /* ExportDeclaration */:
|
|
case 209 /* ImportDeclaration */:
|
|
case 208 /* ImportEqualsDeclaration */:
|
|
case 200 /* FunctionDeclaration */:
|
|
continue;
|
|
}
|
|
writeLine();
|
|
emit(statement);
|
|
}
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("}"); // execute
|
|
}
|
|
function emitSystemModule(node, startIndex) {
|
|
collectExternalModuleInfo(node);
|
|
// System modules has the following shape
|
|
// System.register(['dep-1', ... 'dep-n'], function(exports) {/* module body function */})
|
|
// 'exports' here is a function 'exports<T>(name: string, value: T): T' that is used to publish exported values.
|
|
// 'exports' returns its 'value' argument so in most cases expressions
|
|
// that mutate exported values can be rewritten as:
|
|
// expr -> exports('name', expr).
|
|
// The only exception in this rule is postfix unary operators,
|
|
// see comment to 'emitPostfixUnaryExpression' for more details
|
|
ts.Debug.assert(!exportFunctionForFile);
|
|
// make sure that name of 'exports' function does not conflict with existing identifiers
|
|
exportFunctionForFile = makeUniqueName("exports");
|
|
write("System.register([");
|
|
for (var i = 0; i < externalImports.length; ++i) {
|
|
var text = getExternalModuleNameText(externalImports[i]);
|
|
if (i !== 0) {
|
|
write(", ");
|
|
}
|
|
write(text);
|
|
}
|
|
write("], function(" + exportFunctionForFile + ") {");
|
|
writeLine();
|
|
increaseIndent();
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
emitSystemModuleBody(node, startIndex);
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("});");
|
|
}
|
|
function emitAMDModule(node, startIndex) {
|
|
collectExternalModuleInfo(node);
|
|
// An AMD define function has the following shape:
|
|
// define(id?, dependencies?, factory);
|
|
//
|
|
// This has the shape of
|
|
// define(name, ["module1", "module2"], function (module1Alias) {
|
|
// The location of the alias in the parameter list in the factory function needs to
|
|
// match the position of the module name in the dependency list.
|
|
//
|
|
// To ensure this is true in cases of modules with no aliases, e.g.:
|
|
// `import "module"` or `<amd-dependency path= "a.css" />`
|
|
// we need to add modules without alias names to the end of the dependencies list
|
|
var aliasedModuleNames = []; // names of modules with corresponding parameter in the
|
|
// factory function.
|
|
var unaliasedModuleNames = []; // names of modules with no corresponding parameters in
|
|
// factory function.
|
|
var importAliasNames = []; // names of the parameters in the factory function; these
|
|
// parameters need to match the indexes of the corresponding
|
|
// module names in aliasedModuleNames.
|
|
// Fill in amd-dependency tags
|
|
for (var _i = 0, _a = node.amdDependencies; _i < _a.length; _i++) {
|
|
var amdDependency = _a[_i];
|
|
if (amdDependency.name) {
|
|
aliasedModuleNames.push("\"" + amdDependency.path + "\"");
|
|
importAliasNames.push(amdDependency.name);
|
|
}
|
|
else {
|
|
unaliasedModuleNames.push("\"" + amdDependency.path + "\"");
|
|
}
|
|
}
|
|
for (var _b = 0; _b < externalImports.length; _b++) {
|
|
var importNode = externalImports[_b];
|
|
// Find the name of the external module
|
|
var externalModuleName = getExternalModuleNameText(importNode);
|
|
// Find the name of the module alias, if there is one
|
|
var importAliasName = getLocalNameForExternalImport(importNode);
|
|
if (importAliasName) {
|
|
aliasedModuleNames.push(externalModuleName);
|
|
importAliasNames.push(importAliasName);
|
|
}
|
|
else {
|
|
unaliasedModuleNames.push(externalModuleName);
|
|
}
|
|
}
|
|
writeLine();
|
|
write("define(");
|
|
if (node.amdModuleName) {
|
|
write("\"" + node.amdModuleName + "\", ");
|
|
}
|
|
write("[\"require\", \"exports\"");
|
|
if (aliasedModuleNames.length) {
|
|
write(", ");
|
|
write(aliasedModuleNames.join(", "));
|
|
}
|
|
if (unaliasedModuleNames.length) {
|
|
write(", ");
|
|
write(unaliasedModuleNames.join(", "));
|
|
}
|
|
write("], function (require, exports");
|
|
if (importAliasNames.length) {
|
|
write(", ");
|
|
write(importAliasNames.join(", "));
|
|
}
|
|
write(") {");
|
|
increaseIndent();
|
|
emitExportStarHelper();
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
emitLinesStartingAt(node.statements, startIndex);
|
|
emitTempDeclarations(true);
|
|
emitExportEquals(true);
|
|
decreaseIndent();
|
|
writeLine();
|
|
write("});");
|
|
}
|
|
function emitCommonJSModule(node, startIndex) {
|
|
collectExternalModuleInfo(node);
|
|
emitExportStarHelper();
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
emitLinesStartingAt(node.statements, startIndex);
|
|
emitTempDeclarations(true);
|
|
emitExportEquals(false);
|
|
}
|
|
function emitES6Module(node, startIndex) {
|
|
externalImports = undefined;
|
|
exportSpecifiers = undefined;
|
|
exportEquals = undefined;
|
|
hasExportStars = false;
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
emitLinesStartingAt(node.statements, startIndex);
|
|
emitTempDeclarations(true);
|
|
// Emit exportDefault if it exists will happen as part
|
|
// or normal statement emit.
|
|
}
|
|
function emitExportEquals(emitAsReturn) {
|
|
if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) {
|
|
writeLine();
|
|
emitStart(exportEquals);
|
|
write(emitAsReturn ? "return " : "module.exports = ");
|
|
emit(exportEquals.expression);
|
|
write(";");
|
|
emitEnd(exportEquals);
|
|
}
|
|
}
|
|
function emitDirectivePrologues(statements, startWithNewLine) {
|
|
for (var i = 0; i < statements.length; ++i) {
|
|
if (ts.isPrologueDirective(statements[i])) {
|
|
if (startWithNewLine || i > 0) {
|
|
writeLine();
|
|
}
|
|
emit(statements[i]);
|
|
}
|
|
else {
|
|
// return index of the first non prologue directive
|
|
return i;
|
|
}
|
|
}
|
|
return statements.length;
|
|
}
|
|
function writeLines(text) {
|
|
var lines = text.split(/\r\n|\r|\n/g);
|
|
for (var i = 0; i < lines.length; ++i) {
|
|
var line = lines[i];
|
|
if (line.length) {
|
|
writeLine();
|
|
write(line);
|
|
}
|
|
}
|
|
}
|
|
function emitSourceFileNode(node) {
|
|
// Start new file on new line
|
|
writeLine();
|
|
emitDetachedComments(node);
|
|
// emit prologue directives prior to __extends
|
|
var startIndex = emitDirectivePrologues(node.statements, false);
|
|
// Only Emit __extends function when target ES5.
|
|
// For target ES6 and above, we can emit classDeclaration as is.
|
|
if ((languageVersion < 2 /* ES6 */) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & 8 /* EmitExtends */)) {
|
|
writeLines(extendsHelper);
|
|
extendsEmitted = true;
|
|
}
|
|
if (!decorateEmitted && resolver.getNodeCheckFlags(node) & 512 /* EmitDecorate */) {
|
|
writeLines(decorateHelper);
|
|
if (compilerOptions.emitDecoratorMetadata) {
|
|
writeLines(metadataHelper);
|
|
}
|
|
decorateEmitted = true;
|
|
}
|
|
if (!paramEmitted && resolver.getNodeCheckFlags(node) & 1024 /* EmitParam */) {
|
|
writeLines(paramHelper);
|
|
paramEmitted = true;
|
|
}
|
|
if (ts.isExternalModule(node)) {
|
|
if (languageVersion >= 2 /* ES6 */) {
|
|
emitES6Module(node, startIndex);
|
|
}
|
|
else if (compilerOptions.module === 2 /* AMD */) {
|
|
emitAMDModule(node, startIndex);
|
|
}
|
|
else if (compilerOptions.module === 3 /* System */) {
|
|
emitSystemModule(node, startIndex);
|
|
}
|
|
else {
|
|
emitCommonJSModule(node, startIndex);
|
|
}
|
|
}
|
|
else {
|
|
externalImports = undefined;
|
|
exportSpecifiers = undefined;
|
|
exportEquals = undefined;
|
|
hasExportStars = false;
|
|
emitCaptureThisForNodeIfNecessary(node);
|
|
emitLinesStartingAt(node.statements, startIndex);
|
|
emitTempDeclarations(true);
|
|
}
|
|
emitLeadingComments(node.endOfFileToken);
|
|
}
|
|
function emitNodeWithoutSourceMap(node, allowGeneratedIdentifiers) {
|
|
if (!node) {
|
|
return;
|
|
}
|
|
if (node.flags & 2 /* Ambient */) {
|
|
return emitOnlyPinnedOrTripleSlashComments(node);
|
|
}
|
|
var emitComments = shouldEmitLeadingAndTrailingComments(node);
|
|
if (emitComments) {
|
|
emitLeadingComments(node);
|
|
}
|
|
emitJavaScriptWorker(node, allowGeneratedIdentifiers);
|
|
if (emitComments) {
|
|
emitTrailingComments(node);
|
|
}
|
|
}
|
|
function shouldEmitLeadingAndTrailingComments(node) {
|
|
switch (node.kind) {
|
|
// All of these entities are emitted in a specialized fashion. As such, we allow
|
|
// the specialized methods for each to handle the comments on the nodes.
|
|
case 202 /* InterfaceDeclaration */:
|
|
case 200 /* FunctionDeclaration */:
|
|
case 209 /* ImportDeclaration */:
|
|
case 208 /* ImportEqualsDeclaration */:
|
|
case 203 /* TypeAliasDeclaration */:
|
|
case 214 /* ExportAssignment */:
|
|
return false;
|
|
case 205 /* ModuleDeclaration */:
|
|
// Only emit the leading/trailing comments for a module if we're actually
|
|
// emitting the module as well.
|
|
return shouldEmitModuleDeclaration(node);
|
|
case 204 /* EnumDeclaration */:
|
|
// Only emit the leading/trailing comments for an enum if we're actually
|
|
// emitting the module as well.
|
|
return shouldEmitEnumDeclaration(node);
|
|
}
|
|
// If this is the expression body of an arrow function that we're down-leveling,
|
|
// then we don't want to emit comments when we emit the body. It will have already
|
|
// been taken care of when we emitted the 'return' statement for the function
|
|
// expression body.
|
|
if (node.kind !== 179 /* Block */ &&
|
|
node.parent &&
|
|
node.parent.kind === 163 /* ArrowFunction */ &&
|
|
node.parent.body === node &&
|
|
compilerOptions.target <= 1 /* ES5 */) {
|
|
return false;
|
|
}
|
|
// Emit comments for everything else.
|
|
return true;
|
|
}
|
|
function emitJavaScriptWorker(node, allowGeneratedIdentifiers) {
|
|
if (allowGeneratedIdentifiers === void 0) { allowGeneratedIdentifiers = true; }
|
|
// Check if the node can be emitted regardless of the ScriptTarget
|
|
switch (node.kind) {
|
|
case 65 /* Identifier */:
|
|
return emitIdentifier(node, allowGeneratedIdentifiers);
|
|
case 129 /* Parameter */:
|
|
return emitParameter(node);
|
|
case 134 /* MethodDeclaration */:
|
|
case 133 /* MethodSignature */:
|
|
return emitMethod(node);
|
|
case 136 /* GetAccessor */:
|
|
case 137 /* SetAccessor */:
|
|
return emitAccessor(node);
|
|
case 93 /* ThisKeyword */:
|
|
return emitThis(node);
|
|
case 91 /* SuperKeyword */:
|
|
return emitSuper(node);
|
|
case 89 /* NullKeyword */:
|
|
return write("null");
|
|
case 95 /* TrueKeyword */:
|
|
return write("true");
|
|
case 80 /* FalseKeyword */:
|
|
return write("false");
|
|
case 7 /* NumericLiteral */:
|
|
case 8 /* StringLiteral */:
|
|
case 9 /* RegularExpressionLiteral */:
|
|
case 10 /* NoSubstitutionTemplateLiteral */:
|
|
case 11 /* TemplateHead */:
|
|
case 12 /* TemplateMiddle */:
|
|
case 13 /* TemplateTail */:
|
|
return emitLiteral(node);
|
|
case 171 /* TemplateExpression */:
|
|
return emitTemplateExpression(node);
|
|
case 176 /* TemplateSpan */:
|
|
return emitTemplateSpan(node);
|
|
case 126 /* QualifiedName */:
|
|
return emitQualifiedName(node);
|
|
case 150 /* ObjectBindingPattern */:
|
|
return emitObjectBindingPattern(node);
|
|
case 151 /* ArrayBindingPattern */:
|
|
return emitArrayBindingPattern(node);
|
|
case 152 /* BindingElement */:
|
|
return emitBindingElement(node);
|
|
case 153 /* ArrayLiteralExpression */:
|
|
return emitArrayLiteral(node);
|
|
case 154 /* ObjectLiteralExpression */:
|
|
return emitObjectLiteral(node);
|
|
case 224 /* PropertyAssignment */:
|
|
return emitPropertyAssignment(node);
|
|
case 225 /* ShorthandPropertyAssignment */:
|
|
return emitShorthandPropertyAssignment(node);
|
|
case 127 /* ComputedPropertyName */:
|
|
return emitComputedPropertyName(node);
|
|
case 155 /* PropertyAccessExpression */:
|
|
return emitPropertyAccess(node);
|
|
case 156 /* ElementAccessExpression */:
|
|
return emitIndexedAccess(node);
|
|
case 157 /* CallExpression */:
|
|
return emitCallExpression(node);
|
|
case 158 /* NewExpression */:
|
|
return emitNewExpression(node);
|
|
case 159 /* TaggedTemplateExpression */:
|
|
return emitTaggedTemplateExpression(node);
|
|
case 160 /* TypeAssertionExpression */:
|
|
return emit(node.expression);
|
|
case 161 /* ParenthesizedExpression */:
|
|
return emitParenExpression(node);
|
|
case 200 /* FunctionDeclaration */:
|
|
case 162 /* FunctionExpression */:
|
|
case 163 /* ArrowFunction */:
|
|
return emitFunctionDeclaration(node);
|
|
case 164 /* DeleteExpression */:
|
|
return emitDeleteExpression(node);
|
|
case 165 /* TypeOfExpression */:
|
|
return emitTypeOfExpression(node);
|
|
case 166 /* VoidExpression */:
|
|
return emitVoidExpression(node);
|
|
case 167 /* PrefixUnaryExpression */:
|
|
return emitPrefixUnaryExpression(node);
|
|
case 168 /* PostfixUnaryExpression */:
|
|
return emitPostfixUnaryExpression(node);
|
|
case 169 /* BinaryExpression */:
|
|
return emitBinaryExpression(node);
|
|
case 170 /* ConditionalExpression */:
|
|
return emitConditionalExpression(node);
|
|
case 173 /* SpreadElementExpression */:
|
|
return emitSpreadElementExpression(node);
|
|
case 172 /* YieldExpression */:
|
|
return emitYieldExpression(node);
|
|
case 175 /* OmittedExpression */:
|
|
return;
|
|
case 179 /* Block */:
|
|
case 206 /* ModuleBlock */:
|
|
return emitBlock(node);
|
|
case 180 /* VariableStatement */:
|
|
return emitVariableStatement(node);
|
|
case 181 /* EmptyStatement */:
|
|
return write(";");
|
|
case 182 /* ExpressionStatement */:
|
|
return emitExpressionStatement(node);
|
|
case 183 /* IfStatement */:
|
|
return emitIfStatement(node);
|
|
case 184 /* DoStatement */:
|
|
return emitDoStatement(node);
|
|
case 185 /* WhileStatement */:
|
|
return emitWhileStatement(node);
|
|
case 186 /* ForStatement */:
|
|
return emitForStatement(node);
|
|
case 188 /* ForOfStatement */:
|
|
case 187 /* ForInStatement */:
|
|
return emitForInOrForOfStatement(node);
|
|
case 189 /* ContinueStatement */:
|
|
case 190 /* BreakStatement */:
|
|
return emitBreakOrContinueStatement(node);
|
|
case 191 /* ReturnStatement */:
|
|
return emitReturnStatement(node);
|
|
case 192 /* WithStatement */:
|
|
return emitWithStatement(node);
|
|
case 193 /* SwitchStatement */:
|
|
return emitSwitchStatement(node);
|
|
case 220 /* CaseClause */:
|
|
case 221 /* DefaultClause */:
|
|
return emitCaseOrDefaultClause(node);
|
|
case 194 /* LabeledStatement */:
|
|
return emitLabelledStatement(node);
|
|
case 195 /* ThrowStatement */:
|
|
return emitThrowStatement(node);
|
|
case 196 /* TryStatement */:
|
|
return emitTryStatement(node);
|
|
case 223 /* CatchClause */:
|
|
return emitCatchClause(node);
|
|
case 197 /* DebuggerStatement */:
|
|
return emitDebuggerStatement(node);
|
|
case 198 /* VariableDeclaration */:
|
|
return emitVariableDeclaration(node);
|
|
case 174 /* ClassExpression */:
|
|
return emitClassExpression(node);
|
|
case 201 /* ClassDeclaration */:
|
|
return emitClassDeclaration(node);
|
|
case 202 /* InterfaceDeclaration */:
|
|
return emitInterfaceDeclaration(node);
|
|
case 204 /* EnumDeclaration */:
|
|
return emitEnumDeclaration(node);
|
|
case 226 /* EnumMember */:
|
|
return emitEnumMember(node);
|
|
case 205 /* ModuleDeclaration */:
|
|
return emitModuleDeclaration(node);
|
|
case 209 /* ImportDeclaration */:
|
|
return emitImportDeclaration(node);
|
|
case 208 /* ImportEqualsDeclaration */:
|
|
return emitImportEqualsDeclaration(node);
|
|
case 215 /* ExportDeclaration */:
|
|
return emitExportDeclaration(node);
|
|
case 214 /* ExportAssignment */:
|
|
return emitExportAssignment(node);
|
|
case 227 /* SourceFile */:
|
|
return emitSourceFileNode(node);
|
|
}
|
|
}
|
|
function hasDetachedComments(pos) {
|
|
return detachedCommentsInfo !== undefined && lastOrUndefined(detachedCommentsInfo).nodePos === pos;
|
|
}
|
|
function getLeadingCommentsWithoutDetachedComments() {
|
|
// get the leading comments from detachedPos
|
|
var leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, lastOrUndefined(detachedCommentsInfo).detachedCommentEndPos);
|
|
if (detachedCommentsInfo.length - 1) {
|
|
detachedCommentsInfo.pop();
|
|
}
|
|
else {
|
|
detachedCommentsInfo = undefined;
|
|
}
|
|
return leadingComments;
|
|
}
|
|
function filterComments(ranges, onlyPinnedOrTripleSlashComments) {
|
|
// If we're removing comments, then we want to strip out all but the pinned or
|
|
// triple slash comments.
|
|
if (ranges && onlyPinnedOrTripleSlashComments) {
|
|
ranges = ts.filter(ranges, isPinnedOrTripleSlashComment);
|
|
if (ranges.length === 0) {
|
|
return undefined;
|
|
}
|
|
}
|
|
return ranges;
|
|
}
|
|
function getLeadingCommentsToEmit(node) {
|
|
// Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments
|
|
if (node.parent) {
|
|
if (node.parent.kind === 227 /* SourceFile */ || node.pos !== node.parent.pos) {
|
|
if (hasDetachedComments(node.pos)) {
|
|
// get comments without detached comments
|
|
return getLeadingCommentsWithoutDetachedComments();
|
|
}
|
|
else {
|
|
// get the leading comments from the node
|
|
return ts.getLeadingCommentRangesOfNode(node, currentSourceFile);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function getTrailingCommentsToEmit(node) {
|
|
// Emit the trailing comments only if the parent's pos doesn't match because parent should take care of emitting these comments
|
|
if (node.parent) {
|
|
if (node.parent.kind === 227 /* SourceFile */ || node.end !== node.parent.end) {
|
|
return ts.getTrailingCommentRanges(currentSourceFile.text, node.end);
|
|
}
|
|
}
|
|
}
|
|
function emitOnlyPinnedOrTripleSlashComments(node) {
|
|
emitLeadingCommentsWorker(node, true);
|
|
}
|
|
function emitLeadingComments(node) {
|
|
return emitLeadingCommentsWorker(node, compilerOptions.removeComments);
|
|
}
|
|
function emitLeadingCommentsWorker(node, onlyPinnedOrTripleSlashComments) {
|
|
// If the caller only wants pinned or triple slash comments, then always filter
|
|
// down to that set. Otherwise, filter based on the current compiler options.
|
|
var leadingComments = filterComments(getLeadingCommentsToEmit(node), onlyPinnedOrTripleSlashComments);
|
|
ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments);
|
|
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
|
ts.emitComments(currentSourceFile, writer, leadingComments, true, newLine, writeComment);
|
|
}
|
|
function emitTrailingComments(node) {
|
|
// Emit the trailing comments only if the parent's end doesn't match
|
|
var trailingComments = filterComments(getTrailingCommentsToEmit(node), compilerOptions.removeComments);
|
|
// trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
|
|
ts.emitComments(currentSourceFile, writer, trailingComments, false, newLine, writeComment);
|
|
}
|
|
function emitLeadingCommentsOfPosition(pos) {
|
|
var leadingComments;
|
|
if (hasDetachedComments(pos)) {
|
|
// get comments without detached comments
|
|
leadingComments = getLeadingCommentsWithoutDetachedComments();
|
|
}
|
|
else {
|
|
// get the leading comments from the node
|
|
leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, pos);
|
|
}
|
|
leadingComments = filterComments(leadingComments, compilerOptions.removeComments);
|
|
ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, { pos: pos, end: pos }, leadingComments);
|
|
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
|
|
ts.emitComments(currentSourceFile, writer, leadingComments, true, newLine, writeComment);
|
|
}
|
|
function emitDetachedComments(node) {
|
|
var leadingComments = ts.getLeadingCommentRanges(currentSourceFile.text, node.pos);
|
|
if (leadingComments) {
|
|
var detachedComments = [];
|
|
var lastComment;
|
|
ts.forEach(leadingComments, function (comment) {
|
|
if (lastComment) {
|
|
var lastCommentLine = ts.getLineOfLocalPosition(currentSourceFile, lastComment.end);
|
|
var commentLine = ts.getLineOfLocalPosition(currentSourceFile, comment.pos);
|
|
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;
|
|
});
|
|
if (detachedComments.length) {
|
|
// All comments look like they could have been part of the copyright header. Make
|
|
// sure there is at least one blank line between it and the node. If not, it's not
|
|
// a copyright header.
|
|
var lastCommentLine = ts.getLineOfLocalPosition(currentSourceFile, lastOrUndefined(detachedComments).end);
|
|
var nodeLine = ts.getLineOfLocalPosition(currentSourceFile, ts.skipTrivia(currentSourceFile.text, node.pos));
|
|
if (nodeLine >= lastCommentLine + 2) {
|
|
// Valid detachedComments
|
|
ts.emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments);
|
|
ts.emitComments(currentSourceFile, writer, detachedComments, true, newLine, writeComment);
|
|
var currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: lastOrUndefined(detachedComments).end };
|
|
if (detachedCommentsInfo) {
|
|
detachedCommentsInfo.push(currentDetachedCommentInfo);
|
|
}
|
|
else {
|
|
detachedCommentsInfo = [currentDetachedCommentInfo];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function isPinnedOrTripleSlashComment(comment) {
|
|
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === 42 /* asterisk */) {
|
|
return currentSourceFile.text.charCodeAt(comment.pos + 2) === 33 /* exclamation */;
|
|
}
|
|
else if (currentSourceFile.text.charCodeAt(comment.pos + 1) === 47 /* slash */ &&
|
|
comment.pos + 2 < comment.end &&
|
|
currentSourceFile.text.charCodeAt(comment.pos + 2) === 47 /* slash */ &&
|
|
currentSourceFile.text.substring(comment.pos, comment.end).match(ts.fullTripleSlashReferencePathRegEx)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
function emitFile(jsFilePath, sourceFile) {
|
|
emitJavaScript(jsFilePath, sourceFile);
|
|
if (compilerOptions.declaration) {
|
|
ts.writeDeclarationFile(jsFilePath, sourceFile, host, resolver, diagnostics);
|
|
}
|
|
}
|
|
}
|
|
ts.emitFiles = emitFiles;
|
|
})(ts || (ts = {}));
|