/// /// /// /// /// /* @internal */ namespace ts { // Flags enum to track count of temp variables and a few dedicated names const enum TempFlags { Auto = 0x00000000, // No preferred name CountMask = 0x0FFFFFFF, // Temp variable counter _i = 0x10000000, // Use/preference flag for '_i' } // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult { const delimiters = createDelimiterMap(); const brackets = createBracketsMap(); // emit output for the __extends helper function const extendsHelper = ` var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); };`; // Emit output for the __assign helper function. // This is typically used for JSX spread attributes, // and can be used for object literal spread properties. const assignHelper = ` var __assign = (this && this.__assign) || Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; };`; // emit output for the __decorate helper function const decorateHelper = ` var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; };`; // emit output for the __metadata helper function const metadataHelper = ` var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); };`; // emit output for the __param helper function const paramHelper = ` var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } };`; // emit output for the __awaiter helper function const awaiterHelper = ` var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator.throw(value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments)).next()); }); };`; const generatorHelper = ` var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (sent[0] === 1) throw sent[1]; return sent[1]; }, trys: [], stack: [] }, sent, f; function step(op) { if (f) throw new TypeError("Generator is already executing."); while (1) { if (_.done) switch (op[0]) { case 0: return { value: void 0, done: true }; case 1: case 6: throw op[1]; case 2: return { value: op[1], done: true }; } try { switch (f = 1, op[0]) { case 0: case 1: sent = op; break; case 4: return _.label++, { value: op[1], done: false }; case 7: op = _.stack.pop(), _.trys.pop(); continue; default: var r = _.trys.length > 0 && _.trys[_.trys.length - 1]; if (!r && (op[0] === 6 || op[0] === 2)) { _.done = 1; continue; } if (op[0] === 3 && (!r || (op[1] > r[0] && op[1] < r[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < r[1]) { _.label = r[1], sent = op; break; } if (r && _.label < r[2]) { _.label = r[2], _.stack.push(op); break; } if (r[2]) { _.stack.pop(); } _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; } finally { f = 0, sent = void 0; } } } return { next: function (v) { return step([0, v]); }, "throw": function (v) { return step([1, v]); }, "return": function (v) { return step([2, v]); } }; };`; // emit output for the __export helper function const exportStarHelper = ` function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; }`; // emit output for the UMD helper function. const umdHelper = ` (function (dependencies, factory) { if (typeof module === 'object' && typeof module.exports === 'object') { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === 'function' && define.amd) { define(dependencies, factory); } })`; const superHelper = ` const _super = name => super[name];`; const advancedSuperHelper = ` const _super = (function (geti, seti) { const cache = Object.create(null); return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } }); })(name => super[name], (name, value) => super[name] = value);`; const compilerOptions = host.getCompilerOptions(); const languageVersion = getEmitScriptTarget(compilerOptions); const moduleKind = getEmitModuleKind(compilerOptions); const sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined; const emittedFilesList: string[] = compilerOptions.listEmittedFiles ? [] : undefined; const emitterDiagnostics = createDiagnosticCollection(); const newLine = host.getNewLine(); const transformers = getTransformers(compilerOptions); const writer = createTextWriter(newLine); const { write, writeLine, increaseIndent, decreaseIndent } = writer; const sourceMap = createSourceMapWriter(host, writer); const { emitStart, emitEnd, emitTokenStart, emitTokenEnd } = sourceMap; const comments = createCommentWriter(host, writer, sourceMap); const { emitNodeWithComments, emitBodyWithDetachedComments, emitTrailingCommentsOfPosition } = comments; let nodeIdToGeneratedName: string[]; let autoGeneratedIdToGeneratedName: string[]; let generatedNameSet: Map; let tempFlags: TempFlags; let currentSourceFile: SourceFile; let currentText: string; let currentFileIdentifiers: Map; let extendsEmitted: boolean; let assignEmitted: boolean; let decorateEmitted: boolean; let paramEmitted: boolean; let awaiterEmitted: boolean; let isOwnFileEmit: boolean; let emitSkipped = false; performance.mark("beforeTransform"); // Transform the source files const transformed = transformFiles( resolver, host, getSourceFilesToEmit(host, targetSourceFile), transformers); performance.measure("transformTime", "beforeTransform"); // Extract helpers from the result const { getTokenSourceMapRange, isSubstitutionEnabled, isEmitNotificationEnabled, onSubstituteNode, onEmitNode } = transformed; performance.mark("beforePrint"); // Emit each output file forEachTransformedEmitFile(host, transformed.getSourceFiles(), emitFile); // Clean up after transformation transformed.dispose(); performance.measure("printTime", "beforePrint"); return { emitSkipped, diagnostics: emitterDiagnostics.getDiagnostics(), emittedFiles: emittedFilesList, sourceMaps: sourceMapDataList }; function emitFile(jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) { // Make sure not to write js file and source map file if any of them cannot be written if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) { printFile(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit); } else { emitSkipped = true; } if (declarationFilePath) { emitSkipped = writeDeclarationFile(declarationFilePath, getOriginalSourceFiles(sourceFiles), isBundledEmit, host, resolver, emitterDiagnostics) || emitSkipped; } if (!emitSkipped && emittedFilesList) { emittedFilesList.push(jsFilePath); if (sourceMapFilePath) { emittedFilesList.push(sourceMapFilePath); } if (declarationFilePath) { emittedFilesList.push(declarationFilePath); } } } function printFile(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) { sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit); nodeIdToGeneratedName = []; autoGeneratedIdToGeneratedName = []; generatedNameSet = createMap(); isOwnFileEmit = !isBundledEmit; // Emit helpers from all the files if (isBundledEmit && moduleKind) { forEach(sourceFiles, emitEmitHelpers); } // Print each transformed source file. forEach(sourceFiles, printSourceFile); writeLine(); const sourceMappingURL = sourceMap.getSourceMappingURL(); if (sourceMappingURL) { write(`//# ${"sourceMappingURL"}=${sourceMappingURL}`); // Sometimes tools can sometimes see this line as a source mapping url comment } // Write the source map if (compilerOptions.sourceMap && !compilerOptions.inlineSourceMap) { writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap.getText(), /*writeByteOrderMark*/ false); } // Record source map data for the test harness. if (sourceMapDataList) { sourceMapDataList.push(sourceMap.getSourceMapData()); } // Write the output file writeFile(host, emitterDiagnostics, jsFilePath, writer.getText(), compilerOptions.emitBOM); // Reset state sourceMap.reset(); comments.reset(); writer.reset(); tempFlags = TempFlags.Auto; currentSourceFile = undefined; currentText = undefined; extendsEmitted = false; assignEmitted = false; decorateEmitted = false; paramEmitted = false; awaiterEmitted = false; isOwnFileEmit = false; } function printSourceFile(node: SourceFile) { currentSourceFile = node; currentText = node.text; currentFileIdentifiers = node.identifiers; sourceMap.setSourceFile(node); comments.setSourceFile(node); emitNodeWithNotification(node, emitWorker); } /** * Emits a node. */ function emit(node: Node) { emitNodeWithNotification(node, emitWithComments); } /** * Emits a node with comments. * * NOTE: Do not call this method directly. It is part of the emit pipeline * and should only be called indirectly from emit. */ function emitWithComments(node: Node) { emitNodeWithComments(node, emitWithSourceMap); } /** * Emits a node with source maps. * * NOTE: Do not call this method directly. It is part of the emit pipeline * and should only be called indirectly from emitWithComments. */ function emitWithSourceMap(node: Node) { emitNodeWithSourceMap(node, emitWorker); } function emitIdentifierName(node: Identifier) { if (node) { emitNodeWithNotification(node, emitIdentifierNameWithComments); } } function emitIdentifierNameWithComments(node: Identifier) { emitNodeWithComments(node, emitWorker); } /** * Emits an expression node. */ function emitExpression(node: Expression) { emitNodeWithNotification(node, emitExpressionWithComments); } /** * Emits an expression with comments. * * NOTE: Do not call this method directly. It is part of the emitExpression pipeline * and should only be called indirectly from emitExpression. */ function emitExpressionWithComments(node: Expression) { emitNodeWithComments(node, emitExpressionWithSourceMap); } /** * Emits an expression with source maps. * * NOTE: Do not call this method directly. It is part of the emitExpression pipeline * and should only be called indirectly from emitExpressionWithComments. */ function emitExpressionWithSourceMap(node: Expression) { emitNodeWithSourceMap(node, emitExpressionWorker); } /** * Emits a node with emit notification if available. */ function emitNodeWithNotification(node: Node, emitCallback: (node: Node) => void) { if (node) { if (isEmitNotificationEnabled(node)) { onEmitNode(node, emitCallback); } else { emitCallback(node); } } } function emitNodeWithSourceMap(node: Node, emitCallback: (node: Node) => void) { if (node) { emitStart(/*range*/ node, /*contextNode*/ node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); emitCallback(node); emitEnd(/*range*/ node, /*contextNode*/ node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); } } function getSourceMapRange(node: Node) { return node.sourceMapRange || node; } /** * Determines whether to skip leading comment emit for a node. * * We do not emit comments for NotEmittedStatement nodes or any node that has * NodeEmitFlags.NoLeadingComments. * * @param node A Node. */ function shouldSkipLeadingCommentsForNode(node: Node) { return isNotEmittedStatement(node) || (node.emitFlags & NodeEmitFlags.NoLeadingComments) !== 0; } /** * Determines whether to skip source map emit for the start position of a node. * * We do not emit source maps for NotEmittedStatement nodes or any node that * has NodeEmitFlags.NoLeadingSourceMap. * * @param node A Node. */ function shouldSkipLeadingSourceMapForNode(node: Node) { return isNotEmittedStatement(node) || (node.emitFlags & NodeEmitFlags.NoLeadingSourceMap) !== 0; } /** * Determines whether to skip source map emit for the end position of a node. * * We do not emit source maps for NotEmittedStatement nodes or any node that * has NodeEmitFlags.NoTrailingSourceMap. * * @param node A Node. */ function shouldSkipTrailingSourceMapForNode(node: Node) { return isNotEmittedStatement(node) || (node.emitFlags & NodeEmitFlags.NoTrailingSourceMap) !== 0; } /** * Determines whether to skip source map emit for a node and its children. * * We do not emit source maps for a node that has NodeEmitFlags.NoNestedSourceMaps. */ function shouldSkipSourceMapForChildren(node: Node) { return (node.emitFlags & NodeEmitFlags.NoNestedSourceMaps) !== 0; } function emitWorker(node: Node): void { if (tryEmitSubstitute(node, emitWorker, /*isExpression*/ false)) { return; } const kind = node.kind; switch (kind) { // Pseudo-literals case SyntaxKind.TemplateHead: case SyntaxKind.TemplateMiddle: case SyntaxKind.TemplateTail: return emitLiteral(node); // Identifiers case SyntaxKind.Identifier: return emitIdentifier(node); // Reserved words case SyntaxKind.ConstKeyword: case SyntaxKind.DefaultKeyword: case SyntaxKind.ExportKeyword: case SyntaxKind.VoidKeyword: // Strict mode reserved words case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.PublicKeyword: case SyntaxKind.StaticKeyword: // Contextual keywords case SyntaxKind.AbstractKeyword: case SyntaxKind.AnyKeyword: case SyntaxKind.AsyncKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.DeclareKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.ReadonlyKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.GlobalKeyword: return writeTokenNode(node); // Parse tree nodes // Names case SyntaxKind.QualifiedName: return emitQualifiedName(node); case SyntaxKind.ComputedPropertyName: return emitComputedPropertyName(node); // Signature elements case SyntaxKind.TypeParameter: return emitTypeParameter(node); case SyntaxKind.Parameter: return emitParameter(node); case SyntaxKind.Decorator: return emitDecorator(node); // Type members case SyntaxKind.PropertySignature: return emitPropertySignature(node); case SyntaxKind.PropertyDeclaration: return emitPropertyDeclaration(node); case SyntaxKind.MethodSignature: return emitMethodSignature(node); case SyntaxKind.MethodDeclaration: return emitMethodDeclaration(node); case SyntaxKind.Constructor: return emitConstructor(node); case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: return emitAccessorDeclaration(node); case SyntaxKind.CallSignature: return emitCallSignature(node); case SyntaxKind.ConstructSignature: return emitConstructSignature(node); case SyntaxKind.IndexSignature: return emitIndexSignature(node); // Types case SyntaxKind.TypePredicate: return emitTypePredicate(node); case SyntaxKind.TypeReference: return emitTypeReference(node); case SyntaxKind.FunctionType: return emitFunctionType(node); case SyntaxKind.ConstructorType: return emitConstructorType(node); case SyntaxKind.TypeQuery: return emitTypeQuery(node); case SyntaxKind.TypeLiteral: return emitTypeLiteral(node); case SyntaxKind.ArrayType: return emitArrayType(node); case SyntaxKind.TupleType: return emitTupleType(node); case SyntaxKind.UnionType: return emitUnionType(node); case SyntaxKind.IntersectionType: return emitIntersectionType(node); case SyntaxKind.ParenthesizedType: return emitParenthesizedType(node); case SyntaxKind.ExpressionWithTypeArguments: return emitExpressionWithTypeArguments(node); case SyntaxKind.ThisType: return emitThisType(node); case SyntaxKind.LiteralType: return emitLiteralType(node); // Binding patterns case SyntaxKind.ObjectBindingPattern: return emitObjectBindingPattern(node); case SyntaxKind.ArrayBindingPattern: return emitArrayBindingPattern(node); case SyntaxKind.BindingElement: return emitBindingElement(node); // Misc case SyntaxKind.TemplateSpan: return emitTemplateSpan(node); case SyntaxKind.SemicolonClassElement: return emitSemicolonClassElement(node); // Statements case SyntaxKind.Block: return emitBlock(node); case SyntaxKind.VariableStatement: return emitVariableStatement(node); case SyntaxKind.EmptyStatement: return emitEmptyStatement(node); case SyntaxKind.ExpressionStatement: return emitExpressionStatement(node); case SyntaxKind.IfStatement: return emitIfStatement(node); case SyntaxKind.DoStatement: return emitDoStatement(node); case SyntaxKind.WhileStatement: return emitWhileStatement(node); case SyntaxKind.ForStatement: return emitForStatement(node); case SyntaxKind.ForInStatement: return emitForInStatement(node); case SyntaxKind.ForOfStatement: return emitForOfStatement(node); case SyntaxKind.ContinueStatement: return emitContinueStatement(node); case SyntaxKind.BreakStatement: return emitBreakStatement(node); case SyntaxKind.ReturnStatement: return emitReturnStatement(node); case SyntaxKind.WithStatement: return emitWithStatement(node); case SyntaxKind.SwitchStatement: return emitSwitchStatement(node); case SyntaxKind.LabeledStatement: return emitLabeledStatement(node); case SyntaxKind.ThrowStatement: return emitThrowStatement(node); case SyntaxKind.TryStatement: return emitTryStatement(node); case SyntaxKind.DebuggerStatement: return emitDebuggerStatement(node); // Declarations case SyntaxKind.VariableDeclaration: return emitVariableDeclaration(node); case SyntaxKind.VariableDeclarationList: return emitVariableDeclarationList(node); case SyntaxKind.FunctionDeclaration: return emitFunctionDeclaration(node); case SyntaxKind.ClassDeclaration: return emitClassDeclaration(node); case SyntaxKind.InterfaceDeclaration: return emitInterfaceDeclaration(node); case SyntaxKind.TypeAliasDeclaration: return emitTypeAliasDeclaration(node); case SyntaxKind.EnumDeclaration: return emitEnumDeclaration(node); case SyntaxKind.ModuleDeclaration: return emitModuleDeclaration(node); case SyntaxKind.ModuleBlock: return emitModuleBlock(node); case SyntaxKind.CaseBlock: return emitCaseBlock(node); case SyntaxKind.ImportEqualsDeclaration: return emitImportEqualsDeclaration(node); case SyntaxKind.ImportDeclaration: return emitImportDeclaration(node); case SyntaxKind.ImportClause: return emitImportClause(node); case SyntaxKind.NamespaceImport: return emitNamespaceImport(node); case SyntaxKind.NamedImports: return emitNamedImports(node); case SyntaxKind.ImportSpecifier: return emitImportSpecifier(node); case SyntaxKind.ExportAssignment: return emitExportAssignment(node); case SyntaxKind.ExportDeclaration: return emitExportDeclaration(node); case SyntaxKind.NamedExports: return emitNamedExports(node); case SyntaxKind.ExportSpecifier: return emitExportSpecifier(node); case SyntaxKind.MissingDeclaration: return; // Module references case SyntaxKind.ExternalModuleReference: return emitExternalModuleReference(node); // JSX (non-expression) case SyntaxKind.JsxText: return emitJsxText(node); case SyntaxKind.JsxOpeningElement: return emitJsxOpeningElement(node); case SyntaxKind.JsxClosingElement: return emitJsxClosingElement(node); case SyntaxKind.JsxAttribute: return emitJsxAttribute(node); case SyntaxKind.JsxSpreadAttribute: return emitJsxSpreadAttribute(node); case SyntaxKind.JsxExpression: return emitJsxExpression(node); // Clauses case SyntaxKind.CaseClause: return emitCaseClause(node); case SyntaxKind.DefaultClause: return emitDefaultClause(node); case SyntaxKind.HeritageClause: return emitHeritageClause(node); case SyntaxKind.CatchClause: return emitCatchClause(node); // Property assignments case SyntaxKind.PropertyAssignment: return emitPropertyAssignment(node); case SyntaxKind.ShorthandPropertyAssignment: return emitShorthandPropertyAssignment(node); // Enum case SyntaxKind.EnumMember: return emitEnumMember(node); // Top-level nodes case SyntaxKind.SourceFile: return emitSourceFile(node); // JSDoc nodes (ignored) // Transformation nodes (ignored) } if (isExpression(node)) { return emitExpressionWorker(node); } } function emitExpressionWorker(node: Node) { if (tryEmitSubstitute(node, emitExpressionWorker, /*isExpression*/ true)) { return; } const kind = node.kind; switch (kind) { // Literals case SyntaxKind.NumericLiteral: return emitNumericLiteral(node); case SyntaxKind.StringLiteral: case SyntaxKind.RegularExpressionLiteral: case SyntaxKind.NoSubstitutionTemplateLiteral: return emitLiteral(node); // Identifiers case SyntaxKind.Identifier: return emitIdentifier(node); // Reserved words case SyntaxKind.FalseKeyword: case SyntaxKind.NullKeyword: case SyntaxKind.SuperKeyword: case SyntaxKind.TrueKeyword: case SyntaxKind.ThisKeyword: return writeTokenNode(node); // Expressions case SyntaxKind.ArrayLiteralExpression: return emitArrayLiteralExpression(node); case SyntaxKind.ObjectLiteralExpression: return emitObjectLiteralExpression(node); case SyntaxKind.PropertyAccessExpression: return emitPropertyAccessExpression(node); case SyntaxKind.ElementAccessExpression: return emitElementAccessExpression(node); case SyntaxKind.CallExpression: return emitCallExpression(node); case SyntaxKind.NewExpression: return emitNewExpression(node); case SyntaxKind.TaggedTemplateExpression: return emitTaggedTemplateExpression(node); case SyntaxKind.TypeAssertionExpression: return emitTypeAssertionExpression(node); case SyntaxKind.ParenthesizedExpression: return emitParenthesizedExpression(node); case SyntaxKind.FunctionExpression: return emitFunctionExpression(node); case SyntaxKind.ArrowFunction: return emitArrowFunction(node); case SyntaxKind.DeleteExpression: return emitDeleteExpression(node); case SyntaxKind.TypeOfExpression: return emitTypeOfExpression(node); case SyntaxKind.VoidExpression: return emitVoidExpression(node); case SyntaxKind.AwaitExpression: return emitAwaitExpression(node); case SyntaxKind.PrefixUnaryExpression: return emitPrefixUnaryExpression(node); case SyntaxKind.PostfixUnaryExpression: return emitPostfixUnaryExpression(node); case SyntaxKind.BinaryExpression: return emitBinaryExpression(node); case SyntaxKind.ConditionalExpression: return emitConditionalExpression(node); case SyntaxKind.TemplateExpression: return emitTemplateExpression(node); case SyntaxKind.YieldExpression: return emitYieldExpression(node); case SyntaxKind.SpreadElementExpression: return emitSpreadElementExpression(node); case SyntaxKind.ClassExpression: return emitClassExpression(node); case SyntaxKind.OmittedExpression: return; case SyntaxKind.AsExpression: return emitAsExpression(node); case SyntaxKind.NonNullExpression: return emitNonNullExpression(node); // JSX case SyntaxKind.JsxElement: return emitJsxElement(node); case SyntaxKind.JsxSelfClosingElement: return emitJsxSelfClosingElement(node); // Transformation nodes case SyntaxKind.PartiallyEmittedExpression: return emitPartiallyEmittedExpression(node); } } // // Literals/Pseudo-literals // // SyntaxKind.NumericLiteral function emitNumericLiteral(node: NumericLiteral) { emitLiteral(node); if (node.trailingComment) { write(` /*${node.trailingComment}*/`); } } // SyntaxKind.StringLiteral // SyntaxKind.RegularExpressionLiteral // SyntaxKind.NoSubstitutionTemplateLiteral // SyntaxKind.TemplateHead // SyntaxKind.TemplateMiddle // SyntaxKind.TemplateTail function emitLiteral(node: LiteralLikeNode) { const text = getLiteralTextOfNode(node); if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { writer.writeLiteral(text); } else { write(text); } } // // Identifiers // function emitIdentifier(node: Identifier) { if (node.emitFlags & NodeEmitFlags.UMDDefine) { writeLines(umdHelper); } else { write(getTextOfNode(node, /*includeTrivia*/ false)); } } // // Names // function emitQualifiedName(node: QualifiedName) { emitEntityName(node.left); write("."); emit(node.right); } function emitEntityName(node: EntityName) { if (node.kind === SyntaxKind.Identifier) { emitExpression(node); } else { emit(node); } } function emitComputedPropertyName(node: ComputedPropertyName) { write("["); emitExpression(node.expression); write("]"); } // // Signature elements // function emitTypeParameter(node: TypeParameterDeclaration) { emit(node.name); emitWithPrefix(" extends ", node.constraint); } function emitParameter(node: ParameterDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); writeIfPresent(node.dotDotDotToken, "..."); emit(node.name); writeIfPresent(node.questionToken, "?"); emitExpressionWithPrefix(" = ", node.initializer); emitWithPrefix(": ", node.type); } function emitDecorator(decorator: Decorator) { write("@"); emitExpression(decorator.expression); } // // Type members // function emitPropertySignature(node: PropertySignature) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emit(node.name); writeIfPresent(node.questionToken, "?"); emitWithPrefix(": ", node.type); write(";"); } function emitPropertyDeclaration(node: PropertyDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emit(node.name); emitWithPrefix(": ", node.type); emitExpressionWithPrefix(" = ", node.initializer); write(";"); } function emitMethodSignature(node: MethodSignature) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emit(node.name); writeIfPresent(node.questionToken, "?"); emitTypeParameters(node, node.typeParameters); emitParameters(node, node.parameters); emitWithPrefix(": ", node.type); write(";"); } function emitMethodDeclaration(node: MethodDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); writeIfPresent(node.asteriskToken, "*"); emit(node.name); emitSignatureAndBody(node, emitSignatureHead); } function emitConstructor(node: ConstructorDeclaration) { emitModifiers(node, node.modifiers); write("constructor"); emitSignatureAndBody(node, emitSignatureHead); } function emitAccessorDeclaration(node: AccessorDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); emit(node.name); emitSignatureAndBody(node, emitSignatureHead); } function emitCallSignature(node: CallSignatureDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emitTypeParameters(node, node.typeParameters); emitParameters(node, node.parameters); emitWithPrefix(": ", node.type); write(";"); } function emitConstructSignature(node: ConstructSignatureDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); write("new "); emitTypeParameters(node, node.typeParameters); emitParameters(node, node.parameters); emitWithPrefix(": ", node.type); write(";"); } function emitIndexSignature(node: IndexSignatureDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emitParametersForIndexSignature(node, node.parameters); emitWithPrefix(": ", node.type); write(";"); } function emitSemicolonClassElement(node: SemicolonClassElement) { write(";"); } // // Types // function emitTypePredicate(node: TypePredicateNode) { emit(node.parameterName); write(" is "); emit(node.type); } function emitTypeReference(node: TypeReferenceNode) { emit(node.typeName); emitTypeArguments(node, node.typeArguments); } function emitFunctionType(node: FunctionTypeNode) { emitTypeParameters(node, node.typeParameters); emitParametersForArrow(node, node.parameters); write(" => "); emit(node.type); } function emitConstructorType(node: ConstructorTypeNode) { write("new "); emitTypeParameters(node, node.typeParameters); emitParametersForArrow(node, node.parameters); write(" => "); emit(node.type); } function emitTypeQuery(node: TypeQueryNode) { write("typeof "); emit(node.exprName); } function emitTypeLiteral(node: TypeLiteralNode) { write("{"); emitList(node, node.members, ListFormat.TypeLiteralMembers); write("}"); } function emitArrayType(node: ArrayTypeNode) { emit(node.elementType); write("[]"); } function emitTupleType(node: TupleTypeNode) { write("["); emitList(node, node.elementTypes, ListFormat.TupleTypeElements); write("]"); } function emitUnionType(node: UnionTypeNode) { emitList(node, node.types, ListFormat.UnionTypeConstituents); } function emitIntersectionType(node: IntersectionTypeNode) { emitList(node, node.types, ListFormat.IntersectionTypeConstituents); } function emitParenthesizedType(node: ParenthesizedTypeNode) { write("("); emit(node.type); write(")"); } function emitThisType(node: ThisTypeNode) { write("this"); } function emitLiteralType(node: LiteralTypeNode) { emitExpression(node.literal); } // // Binding patterns // function emitObjectBindingPattern(node: ObjectBindingPattern) { const elements = node.elements; if (elements.length === 0) { write("{}"); } else { write("{"); emitList(node, elements, ListFormat.ObjectBindingPatternElements); write("}"); } } function emitArrayBindingPattern(node: ArrayBindingPattern) { const elements = node.elements; if (elements.length === 0) { write("[]"); } else { write("["); emitList(node, node.elements, ListFormat.ArrayBindingPatternElements); write("]"); } } function emitBindingElement(node: BindingElement) { emitWithSuffix(node.propertyName, ": "); writeIfPresent(node.dotDotDotToken, "..."); emit(node.name); emitExpressionWithPrefix(" = ", node.initializer); } // // Expressions // function emitArrayLiteralExpression(node: ArrayLiteralExpression) { const elements = node.elements; if (elements.length === 0) { write("[]"); } else { const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine); } } function emitObjectLiteralExpression(node: ObjectLiteralExpression) { const properties = node.properties; if (properties.length === 0) { write("{}"); } else { const indentedFlag = node.emitFlags & NodeEmitFlags.Indented; if (indentedFlag) { increaseIndent(); } const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; const allowTrailingComma = languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None; emitList(node, properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine); if (indentedFlag) { decreaseIndent(); } } } function emitPropertyAccessExpression(node: PropertyAccessExpression) { if (tryEmitConstantValue(node)) { return; } let indentBeforeDot = false; let indentAfterDot = false; if (!(node.emitFlags & NodeEmitFlags.NoIndentation)) { const dotRangeStart = node.expression.end; const dotRangeEnd = skipTrivia(currentText, node.expression.end) + 1; const dotToken = { kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd }; indentBeforeDot = needsIndentation(node, node.expression, dotToken); indentAfterDot = needsIndentation(node, dotToken, node.name); } const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression); emitExpression(node.expression); increaseIndentIf(indentBeforeDot); write(shouldEmitDotDot ? ".." : "."); increaseIndentIf(indentAfterDot); emit(node.name); decreaseIndentIf(indentBeforeDot, indentAfterDot); } // 1..toString is a valid property access, emit a dot after the literal // Also emit a dot if expression is a integer const enum value - it will appear in generated code as numeric literal function needsDotDotForPropertyAccess(expression: Expression) { if (expression.kind === SyntaxKind.NumericLiteral) { // check if numeric literal was originally written with a dot const text = getLiteralTextOfNode(expression); return text.indexOf(tokenToString(SyntaxKind.DotToken)) < 0; } else { // check if constant enum value is integer const constantValue = tryGetConstEnumValue(expression); // isFinite handles cases when constantValue is undefined return isFinite(constantValue) && Math.floor(constantValue) === constantValue; } } function emitElementAccessExpression(node: ElementAccessExpression) { if (tryEmitConstantValue(node)) { return; } emitExpression(node.expression); write("["); emitExpression(node.argumentExpression); write("]"); } function emitCallExpression(node: CallExpression) { emitExpression(node.expression); emitExpressionList(node, node.arguments, ListFormat.CallExpressionArguments); } function emitNewExpression(node: NewExpression) { write("new "); emitExpression(node.expression); emitExpressionList(node, node.arguments, ListFormat.NewExpressionArguments); } function emitTaggedTemplateExpression(node: TaggedTemplateExpression) { emitExpression(node.tag); write(" "); emitExpression(node.template); } function emitTypeAssertionExpression(node: TypeAssertion) { if (node.type) { write("<"); emit(node.type); write(">"); } emitExpression(node.expression); } function emitParenthesizedExpression(node: ParenthesizedExpression) { write("("); emitExpression(node.expression); write(")"); } function emitFunctionExpression(node: FunctionExpression) { emitFunctionDeclarationOrExpression(node); } function emitArrowFunction(node: ArrowFunction) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emitSignatureAndBody(node, emitArrowFunctionHead); } function emitArrowFunctionHead(node: ArrowFunction) { emitTypeParameters(node, node.typeParameters); emitParametersForArrow(node, node.parameters); emitWithPrefix(": ", node.type); write(" =>"); } function emitDeleteExpression(node: DeleteExpression) { write("delete "); emitExpression(node.expression); } function emitTypeOfExpression(node: TypeOfExpression) { write("typeof "); emitExpression(node.expression); } function emitVoidExpression(node: VoidExpression) { write("void "); emitExpression(node.expression); } function emitAwaitExpression(node: AwaitExpression) { write("await "); emitExpression(node.expression); } function emitPrefixUnaryExpression(node: PrefixUnaryExpression) { writeTokenText(node.operator); if (shouldEmitWhitespaceBeforeOperand(node)) { write(" "); } emitExpression(node.operand); } function shouldEmitWhitespaceBeforeOperand(node: PrefixUnaryExpression) { // 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. const operand = node.operand; return operand.kind === SyntaxKind.PrefixUnaryExpression && ((node.operator === SyntaxKind.PlusToken && ((operand).operator === SyntaxKind.PlusToken || (operand).operator === SyntaxKind.PlusPlusToken)) || (node.operator === SyntaxKind.MinusToken && ((operand).operator === SyntaxKind.MinusToken || (operand).operator === SyntaxKind.MinusMinusToken))); } function emitPostfixUnaryExpression(node: PostfixUnaryExpression) { emitExpression(node.operand); writeTokenText(node.operator); } function emitBinaryExpression(node: BinaryExpression) { const isCommaOperator = node.operatorToken.kind !== SyntaxKind.CommaToken; const indentBeforeOperator = needsIndentation(node, node.left, node.operatorToken); const indentAfterOperator = needsIndentation(node, node.operatorToken, node.right); emitExpression(node.left); increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined); writeTokenText(node.operatorToken.kind); increaseIndentIf(indentAfterOperator, " "); emitExpression(node.right); decreaseIndentIf(indentBeforeOperator, indentAfterOperator); } function emitConditionalExpression(node: ConditionalExpression) { const indentBeforeQuestion = needsIndentation(node, node.condition, node.questionToken); const indentAfterQuestion = needsIndentation(node, node.questionToken, node.whenTrue); const indentBeforeColon = needsIndentation(node, node.whenTrue, node.colonToken); const indentAfterColon = needsIndentation(node, node.colonToken, node.whenFalse); emitExpression(node.condition); increaseIndentIf(indentBeforeQuestion, " "); write("?"); increaseIndentIf(indentAfterQuestion, " "); emitExpression(node.whenTrue); decreaseIndentIf(indentBeforeQuestion, indentAfterQuestion); increaseIndentIf(indentBeforeColon, " "); write(":"); increaseIndentIf(indentAfterColon, " "); emitExpression(node.whenFalse); decreaseIndentIf(indentBeforeColon, indentAfterColon); } function emitTemplateExpression(node: TemplateExpression) { emit(node.head); emitList(node, node.templateSpans, ListFormat.TemplateExpressionSpans); } function emitYieldExpression(node: YieldExpression) { write(node.asteriskToken ? "yield*" : "yield"); emitExpressionWithPrefix(" ", node.expression); } function emitSpreadElementExpression(node: SpreadElementExpression) { write("..."); emitExpression(node.expression); } function emitClassExpression(node: ClassExpression) { emitClassDeclarationOrExpression(node); } function emitExpressionWithTypeArguments(node: ExpressionWithTypeArguments) { emitExpression(node.expression); emitTypeArguments(node, node.typeArguments); } function emitAsExpression(node: AsExpression) { emitExpression(node.expression); if (node.type) { write(" as "); emit(node.type); } } function emitNonNullExpression(node: NonNullExpression) { emitExpression(node.expression); write("!"); } // // Misc // function emitTemplateSpan(node: TemplateSpan) { emitExpression(node.expression); emit(node.literal); } // // Statements // function emitBlock(node: Block, format?: ListFormat) { if (isSingleLineEmptyBlock(node)) { writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node); write(" "); writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node); } else { writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node); emitBlockStatements(node); writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node); } } function emitBlockStatements(node: Block) { if (node.emitFlags & NodeEmitFlags.SingleLine) { emitList(node, node.statements, ListFormat.SingleLineBlockStatements); } else { emitList(node, node.statements, ListFormat.MultiLineBlockStatements); } } function emitVariableStatement(node: VariableStatement) { emitModifiers(node, node.modifiers); emit(node.declarationList); write(";"); } function emitEmptyStatement(node: EmptyStatement) { write(";"); } function emitExpressionStatement(node: ExpressionStatement) { emitExpression(node.expression); write(";"); } function emitIfStatement(node: IfStatement) { const openParenPos = writeToken(SyntaxKind.IfKeyword, node.pos, node); write(" "); writeToken(SyntaxKind.OpenParenToken, openParenPos, node); emitExpression(node.expression); writeToken(SyntaxKind.CloseParenToken, node.expression.end, node); emitEmbeddedStatement(node.thenStatement); if (node.elseStatement) { writeLine(); writeToken(SyntaxKind.ElseKeyword, node.thenStatement.end, node); if (node.elseStatement.kind === SyntaxKind.IfStatement) { write(" "); emit(node.elseStatement); } else { emitEmbeddedStatement(node.elseStatement); } } } function emitDoStatement(node: DoStatement) { write("do"); emitEmbeddedStatement(node.statement); if (isBlock(node.statement)) { write(" "); } else { writeLine(); } write("while ("); emitExpression(node.expression); write(");"); } function emitWhileStatement(node: WhileStatement) { write("while ("); emitExpression(node.expression); write(")"); emitEmbeddedStatement(node.statement); } function emitForStatement(node: ForStatement) { const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos); write(" "); writeToken(SyntaxKind.OpenParenToken, openParenPos, /*contextNode*/ node); emitForBinding(node.initializer); write(";"); emitExpressionWithPrefix(" ", node.condition); write(";"); emitExpressionWithPrefix(" ", node.incrementor); write(")"); emitEmbeddedStatement(node.statement); } function emitForInStatement(node: ForInStatement) { const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos); write(" "); writeToken(SyntaxKind.OpenParenToken, openParenPos); emitForBinding(node.initializer); write(" in "); emitExpression(node.expression); writeToken(SyntaxKind.CloseParenToken, node.expression.end); emitEmbeddedStatement(node.statement); } function emitForOfStatement(node: ForOfStatement) { const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos); write(" "); writeToken(SyntaxKind.OpenParenToken, openParenPos); emitForBinding(node.initializer); write(" of "); emitExpression(node.expression); writeToken(SyntaxKind.CloseParenToken, node.expression.end); emitEmbeddedStatement(node.statement); } function emitForBinding(node: VariableDeclarationList | Expression) { if (node !== undefined) { if (node.kind === SyntaxKind.VariableDeclarationList) { emit(node); } else { emitExpression(node); } } } function emitContinueStatement(node: ContinueStatement) { writeToken(SyntaxKind.ContinueKeyword, node.pos); emitWithPrefix(" ", node.label); write(";"); } function emitBreakStatement(node: BreakStatement) { writeToken(SyntaxKind.BreakKeyword, node.pos); emitWithPrefix(" ", node.label); write(";"); } function emitReturnStatement(node: ReturnStatement) { writeToken(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node); emitExpressionWithPrefix(" ", node.expression); write(";"); } function emitWithStatement(node: WithStatement) { write("with ("); emitExpression(node.expression); write(")"); emitEmbeddedStatement(node.statement); } function emitSwitchStatement(node: SwitchStatement) { const openParenPos = writeToken(SyntaxKind.SwitchKeyword, node.pos); write(" "); writeToken(SyntaxKind.OpenParenToken, openParenPos); emitExpression(node.expression); writeToken(SyntaxKind.CloseParenToken, node.expression.end); write(" "); emit(node.caseBlock); } function emitLabeledStatement(node: LabeledStatement) { emit(node.label); write(": "); emit(node.statement); } function emitThrowStatement(node: ThrowStatement) { write("throw"); emitExpressionWithPrefix(" ", node.expression); write(";"); } function emitTryStatement(node: TryStatement) { write("try "); emit(node.tryBlock); emit(node.catchClause); if (node.finallyBlock) { writeLine(); write("finally "); emit(node.finallyBlock); } } function emitDebuggerStatement(node: DebuggerStatement) { writeToken(SyntaxKind.DebuggerKeyword, node.pos); write(";"); } // // Declarations // function emitVariableDeclaration(node: VariableDeclaration) { emit(node.name); emitExpressionWithPrefix(" = ", node.initializer); } function emitVariableDeclarationList(node: VariableDeclarationList) { write(isLet(node) ? "let " : isConst(node) ? "const " : "var "); emitList(node, node.declarations, ListFormat.VariableDeclarationList); } function emitFunctionDeclaration(node: FunctionDeclaration) { emitFunctionDeclarationOrExpression(node); } function emitFunctionDeclarationOrExpression(node: FunctionDeclaration | FunctionExpression) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); write(node.asteriskToken ? "function* " : "function "); emitIdentifierName(node.name); emitSignatureAndBody(node, emitSignatureHead); } function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) { const body = node.body; if (body) { if (isBlock(body)) { const indentedFlag = node.emitFlags & NodeEmitFlags.Indented; if (indentedFlag) { increaseIndent(); } if (node.emitFlags & NodeEmitFlags.ReuseTempVariableScope) { emitSignatureHead(node); emitBlockFunctionBody(node, body); } else { const savedTempFlags = tempFlags; tempFlags = 0; emitSignatureHead(node); emitBlockFunctionBody(node, body); tempFlags = savedTempFlags; } if (indentedFlag) { decreaseIndent(); } } else { emitSignatureHead(node); write(" "); emitExpression(body); } } else { emitSignatureHead(node); write(";"); } } function emitSignatureHead(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) { emitTypeParameters(node, node.typeParameters); emitParameters(node, node.parameters); emitWithPrefix(": ", node.type); } function shouldEmitBlockFunctionBodyOnSingleLine(parentNode: Node, body: Block) { // We must emit a function body as a single-line body in the following case: // * The body has NodeEmitFlags.SingleLine specified. // We must emit a function body as a multi-line body in the following cases: // * The body is explicitly marked as multi-line. // * A non-synthesized body's start and end position are on different lines. // * Any statement in the body starts on a new line. if (body.emitFlags & NodeEmitFlags.SingleLine) { return true; } if (body.multiLine) { return false; } if (!nodeIsSynthesized(body) && !rangeIsOnSingleLine(body, currentSourceFile)) { return false; } if (shouldWriteLeadingLineTerminator(body, body.statements, ListFormat.PreserveLines) || shouldWriteClosingLineTerminator(body, body.statements, ListFormat.PreserveLines)) { return false; } let previousStatement: Statement; for (const statement of body.statements) { if (shouldWriteSeparatingLineTerminator(previousStatement, statement, ListFormat.PreserveLines)) { return false; } previousStatement = statement; } return true; } function emitBlockFunctionBody(parentNode: Node, body: Block) { write(" {"); increaseIndent(); emitBodyWithDetachedComments(body, body.statements, shouldEmitBlockFunctionBodyOnSingleLine(parentNode, body) ? emitBlockFunctionBodyOnSingleLine : emitBlockFunctionBodyWorker); decreaseIndent(); writeToken(SyntaxKind.CloseBraceToken, body.statements.end, body); } function emitBlockFunctionBodyOnSingleLine(body: Block) { emitBlockFunctionBodyWorker(body, /*emitBlockFunctionBodyOnSingleLine*/ true); } function emitBlockFunctionBodyWorker(body: Block, emitBlockFunctionBodyOnSingleLine?: boolean) { // Emit all the prologue directives (like "use strict"). const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true); const helpersEmitted = emitHelpers(body); if (statementOffset === 0 && !helpersEmitted && emitBlockFunctionBodyOnSingleLine) { decreaseIndent(); emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements); increaseIndent(); } else { emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset); } } function emitClassDeclaration(node: ClassDeclaration) { emitClassDeclarationOrExpression(node); } function emitClassDeclarationOrExpression(node: ClassDeclaration | ClassExpression) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); write("class"); emitNodeWithPrefix(" ", node.name, emitIdentifierName); const indentedFlag = node.emitFlags & NodeEmitFlags.Indented; if (indentedFlag) { increaseIndent(); } emitTypeParameters(node, node.typeParameters); emitList(node, node.heritageClauses, ListFormat.ClassHeritageClauses); const savedTempFlags = tempFlags; tempFlags = 0; write(" {"); emitList(node, node.members, ListFormat.ClassMembers); write("}"); if (indentedFlag) { decreaseIndent(); } tempFlags = savedTempFlags; } function emitInterfaceDeclaration(node: InterfaceDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); write("interface "); emit(node.name); emitTypeParameters(node, node.typeParameters); emitList(node, node.heritageClauses, ListFormat.HeritageClauses); write(" {"); emitList(node, node.members, ListFormat.InterfaceMembers); write("}"); } function emitTypeAliasDeclaration(node: TypeAliasDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); write("type "); emit(node.name); emitTypeParameters(node, node.typeParameters); write(" = "); emit(node.type); write(";"); } function emitEnumDeclaration(node: EnumDeclaration) { emitModifiers(node, node.modifiers); write("enum "); emit(node.name); const savedTempFlags = tempFlags; tempFlags = 0; write(" {"); emitList(node, node.members, ListFormat.EnumMembers); write("}"); tempFlags = savedTempFlags; } function emitModuleDeclaration(node: ModuleDeclaration) { emitModifiers(node, node.modifiers); write(node.flags & NodeFlags.Namespace ? "namespace " : "module "); emit(node.name); let body = node.body; while (body.kind === SyntaxKind.ModuleDeclaration) { write("."); emit((body).name); body = (body).body; } write(" "); emit(body); } function emitModuleBlock(node: ModuleBlock) { if (isSingleLineEmptyBlock(node)) { write("{ }"); } else { const savedTempFlags = tempFlags; tempFlags = 0; write("{"); increaseIndent(); emitBlockStatements(node); write("}"); tempFlags = savedTempFlags; } } function emitCaseBlock(node: CaseBlock) { writeToken(SyntaxKind.OpenBraceToken, node.pos); emitList(node, node.clauses, ListFormat.CaseBlockClauses); writeToken(SyntaxKind.CloseBraceToken, node.clauses.end); } function emitImportEqualsDeclaration(node: ImportEqualsDeclaration) { emitModifiers(node, node.modifiers); write("import "); emit(node.name); write(" = "); emitModuleReference(node.moduleReference); write(";"); } function emitModuleReference(node: ModuleReference) { if (node.kind === SyntaxKind.Identifier) { emitExpression(node); } else { emit(node); } } function emitImportDeclaration(node: ImportDeclaration) { emitModifiers(node, node.modifiers); write("import "); if (node.importClause) { emit(node.importClause); write(" from "); } emitExpression(node.moduleSpecifier); write(";"); } function emitImportClause(node: ImportClause) { emit(node.name); if (node.name && node.namedBindings) { write(", "); } emit(node.namedBindings); } function emitNamespaceImport(node: NamespaceImport) { write("* as "); emit(node.name); } function emitNamedImports(node: NamedImports) { emitNamedImportsOrExports(node); } function emitImportSpecifier(node: ImportSpecifier) { emitImportOrExportSpecifier(node); } function emitExportAssignment(node: ExportAssignment) { write(node.isExportEquals ? "export = " : "export default "); emitExpression(node.expression); write(";"); } function emitExportDeclaration(node: ExportDeclaration) { write("export "); if (node.exportClause) { emit(node.exportClause); } else { write("*"); } if (node.moduleSpecifier) { write(" from "); emitExpression(node.moduleSpecifier); } write(";"); } function emitNamedExports(node: NamedExports) { emitNamedImportsOrExports(node); } function emitExportSpecifier(node: ExportSpecifier) { emitImportOrExportSpecifier(node); } function emitNamedImportsOrExports(node: NamedImportsOrExports) { write("{"); emitList(node, node.elements, ListFormat.NamedImportsOrExportsElements); write("}"); } function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) { if (node.propertyName) { emit(node.propertyName); write(" as "); } emit(node.name); } // // Module references // function emitExternalModuleReference(node: ExternalModuleReference) { write("require("); emitExpression(node.expression); write(")"); } // // JSX // function emitJsxElement(node: JsxElement) { emit(node.openingElement); emitList(node, node.children, ListFormat.JsxElementChildren); emit(node.closingElement); } function emitJsxSelfClosingElement(node: JsxSelfClosingElement) { write("<"); emitJsxTagName(node.tagName); write(" "); emitList(node, node.attributes, ListFormat.JsxElementAttributes); write("/>"); } function emitJsxOpeningElement(node: JsxOpeningElement) { write("<"); emitJsxTagName(node.tagName); writeIfAny(node.attributes, " "); emitList(node, node.attributes, ListFormat.JsxElementAttributes); write(">"); } function emitJsxText(node: JsxText) { writer.writeLiteral(getTextOfNode(node, /*includeTrivia*/ true)); } function emitJsxClosingElement(node: JsxClosingElement) { write(""); } function emitJsxAttribute(node: JsxAttribute) { emit(node.name); emitWithPrefix("=", node.initializer); } function emitJsxSpreadAttribute(node: JsxSpreadAttribute) { write("{..."); emitExpression(node.expression); write("}"); } function emitJsxExpression(node: JsxExpression) { if (node.expression) { write("{"); emitExpression(node.expression); write("}"); } } function emitJsxTagName(node: JsxTagNameExpression) { if (node.kind === SyntaxKind.Identifier) { emitExpression(node); } else { emit(node); } } // // Clauses // function emitCaseClause(node: CaseClause) { write("case "); emitExpression(node.expression); write(":"); emitCaseOrDefaultClauseStatements(node, node.statements); } function emitDefaultClause(node: DefaultClause) { write("default:"); emitCaseOrDefaultClauseStatements(node, node.statements); } function emitCaseOrDefaultClauseStatements(parentNode: Node, statements: NodeArray) { const emitAsSingleStatement = statements.length === 1 && ( // treat synthesized nodes as located on the same line for emit purposes nodeIsSynthesized(parentNode) || nodeIsSynthesized(statements[0]) || rangeStartPositionsAreOnSameLine(parentNode, statements[0], currentSourceFile) ); if (emitAsSingleStatement) { write(" "); emit(statements[0]); } else { emitList(parentNode, statements, ListFormat.CaseOrDefaultClauseStatements); } } function emitHeritageClause(node: HeritageClause) { write(" "); writeTokenText(node.token); write(" "); emitList(node, node.types, ListFormat.HeritageClauseTypes); } function emitCatchClause(node: CatchClause) { writeLine(); const openParenPos = writeToken(SyntaxKind.CatchKeyword, node.pos); write(" "); writeToken(SyntaxKind.OpenParenToken, openParenPos); emit(node.variableDeclaration); writeToken(SyntaxKind.CloseParenToken, node.variableDeclaration ? node.variableDeclaration.end : openParenPos); write(" "); emit(node.block); } // // Property assignments // function emitPropertyAssignment(node: PropertyAssignment) { emit(node.name); write(": "); // This is to ensure that we emit comment in the following case: // For example: // obj = { // id: /*comment1*/ ()=>void // } // "comment1" is not considered to be leading comment for node.initializer // but rather a trailing comment on the previous node. const initializer = node.initializer; if (!shouldSkipLeadingCommentsForNode(initializer)) { const commentRange = initializer.commentRange || initializer; emitTrailingCommentsOfPosition(commentRange.pos); } emitExpression(initializer); } function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) { emit(node.name); if (node.objectAssignmentInitializer) { write(" = "); emitExpression(node.objectAssignmentInitializer); } } // // Enum // function emitEnumMember(node: EnumMember) { emit(node.name); emitExpressionWithPrefix(" = ", node.initializer); } // // Top-level nodes // function emitSourceFile(node: SourceFile) { writeLine(); emitShebang(); emitBodyWithDetachedComments(node, node.statements, emitSourceFileWorker); } function emitSourceFileWorker(node: SourceFile) { const statements = node.statements; const statementOffset = emitPrologueDirectives(statements); const savedTempFlags = tempFlags; tempFlags = 0; emitHelpers(node); emitList(node, statements, ListFormat.MultiLine, statementOffset); tempFlags = savedTempFlags; } // Transformation nodes function emitPartiallyEmittedExpression(node: PartiallyEmittedExpression) { emitExpression(node.expression); } /** * Emits any prologue directives at the start of a Statement list, returning the * number of prologue directives written to the output. */ function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean): number { for (let i = 0; i < statements.length; i++) { if (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 emitHelpers(node: Node) { const emitFlags = node.emitFlags; let helpersEmitted = false; if (emitFlags & NodeEmitFlags.EmitEmitHelpers) { helpersEmitted = emitEmitHelpers(currentSourceFile); } if (emitFlags & NodeEmitFlags.EmitExportStar) { writeLines(exportStarHelper); helpersEmitted = true; } if (emitFlags & NodeEmitFlags.EmitSuperHelper) { writeLines(superHelper); helpersEmitted = true; } if (emitFlags & NodeEmitFlags.EmitAdvancedSuperHelper) { writeLines(advancedSuperHelper); helpersEmitted = true; } return helpersEmitted; } function emitEmitHelpers(node: SourceFile) { // Only emit helpers if the user did not say otherwise. if (compilerOptions.noEmitHelpers) { return false; } // Don't emit helpers if we can import them. if (compilerOptions.importHelpers && (isExternalModule(node) || compilerOptions.isolatedModules)) { return false; } let helpersEmitted = false; // Only Emit __extends function when target ES5. // For target ES6 and above, we can emit classDeclaration as is. if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && node.flags & NodeFlags.HasClassExtends)) { writeLines(extendsHelper); extendsEmitted = true; helpersEmitted = true; } if (compilerOptions.jsx !== JsxEmit.Preserve && !assignEmitted && (node.flags & NodeFlags.HasJsxSpreadAttributes)) { writeLines(assignHelper); assignEmitted = true; } if (!decorateEmitted && node.flags & NodeFlags.HasDecorators) { writeLines(decorateHelper); if (compilerOptions.emitDecoratorMetadata) { writeLines(metadataHelper); } decorateEmitted = true; helpersEmitted = true; } if (!paramEmitted && node.flags & NodeFlags.HasParamDecorators) { writeLines(paramHelper); paramEmitted = true; helpersEmitted = true; } if (!awaiterEmitted && node.flags & NodeFlags.HasAsyncFunctions) { writeLines(awaiterHelper); if (languageVersion < ScriptTarget.ES6) { writeLines(generatorHelper); } awaiterEmitted = true; helpersEmitted = true; } if (helpersEmitted) { writeLine(); } return helpersEmitted; } function writeLines(text: string): void { const lines = text.split(/\r\n|\r|\n/g); for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line.length) { if (i > 0) { writeLine(); } write(line); } } } // // Helpers // function emitShebang() { const shebang = getShebang(currentText); if (shebang) { write(shebang); writeLine(); } } function emitModifiers(node: Node, modifiers: NodeArray) { if (modifiers && modifiers.length) { emitList(node, modifiers, ListFormat.Modifiers); write(" "); } } function emitWithPrefix(prefix: string, node: Node) { emitNodeWithPrefix(prefix, node, emit); } function emitExpressionWithPrefix(prefix: string, node: Node) { emitNodeWithPrefix(prefix, node, emitExpression); } function emitNodeWithPrefix(prefix: string, node: Node, emit: (node: Node) => void) { if (node) { write(prefix); emit(node); } } function emitWithSuffix(node: Node, suffix: string) { if (node) { emit(node); write(suffix); } } function tryEmitSubstitute(node: Node, emitNode: (node: Node) => void, isExpression: boolean) { if (isSubstitutionEnabled(node) && (node.emitFlags & NodeEmitFlags.NoSubstitution) === 0) { const substitute = onSubstituteNode(node, isExpression); if (substitute !== node) { substitute.emitFlags |= NodeEmitFlags.NoSubstitution; emitNode(substitute); return true; } } return false; } function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean { const constantValue = tryGetConstEnumValue(node); if (constantValue !== undefined) { write(String(constantValue)); if (!compilerOptions.removeComments) { const propertyName = isPropertyAccessExpression(node) ? declarationNameToString(node.name) : getTextOfNode(node.argumentExpression); write(` /* ${propertyName} */`); } return true; } return false; } function emitEmbeddedStatement(node: Statement) { if (isBlock(node)) { write(" "); emit(node); } else { writeLine(); increaseIndent(); emit(node); decreaseIndent(); } } function emitDecorators(parentNode: Node, decorators: NodeArray) { emitList(parentNode, decorators, ListFormat.Decorators); } function emitTypeArguments(parentNode: Node, typeArguments: NodeArray) { emitList(parentNode, typeArguments, ListFormat.TypeArguments); } function emitTypeParameters(parentNode: Node, typeParameters: NodeArray) { emitList(parentNode, typeParameters, ListFormat.TypeParameters); } function emitParameters(parentNode: Node, parameters: NodeArray) { emitList(parentNode, parameters, ListFormat.Parameters); } function emitParametersForArrow(parentNode: Node, parameters: NodeArray) { if (parameters && parameters.length === 1 && parameters[0].type === undefined && parameters[0].pos === parentNode.pos) { emit(parameters[0]); } else { emitParameters(parentNode, parameters); } } function emitParametersForIndexSignature(parentNode: Node, parameters: NodeArray) { emitList(parentNode, parameters, ListFormat.IndexSignatureParameters); } function emitList(parentNode: Node, children: NodeArray, format: ListFormat, start?: number, count?: number) { emitNodeList(emit, parentNode, children, format, start, count); } function emitExpressionList(parentNode: Node, children: NodeArray, format: ListFormat, start?: number, count?: number) { emitNodeList(emitExpression, parentNode, children, format, start, count); } function emitNodeList(emit: (node: Node) => void, parentNode: Node, children: NodeArray, format: ListFormat, start = 0, count = children ? children.length - start : 0) { const isUndefined = children === undefined; if (isUndefined && format & ListFormat.OptionalIfUndefined) { return; } const isEmpty = isUndefined || children.length === 0 || start >= children.length || count === 0; if (isEmpty && format & ListFormat.OptionalIfEmpty) { return; } if (format & ListFormat.BracketsMask) { write(getOpeningBracket(format)); } if (isEmpty) { // Write a line terminator if the parent node was multi-line if (format & ListFormat.MultiLine) { writeLine(); } else if (format & ListFormat.SpaceBetweenBraces) { write(" "); } } else { // Write the opening line terminator or leading whitespace. const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0; let shouldEmitInterveningComments = mayEmitInterveningComments; if (shouldWriteLeadingLineTerminator(parentNode, children, format)) { writeLine(); shouldEmitInterveningComments = false; } else if (format & ListFormat.SpaceBetweenBraces) { write(" "); } // Increase the indent, if requested. if (format & ListFormat.Indented) { increaseIndent(); } // Emit each child. let previousSibling: Node; let shouldDecreaseIndentAfterEmit: boolean; const delimiter = getDelimiter(format); for (let i = 0; i < count; i++) { const child = children[start + i]; // Write the delimiter if this is not the first node. if (previousSibling) { write(delimiter); // Write either a line terminator or whitespace to separate the elements. if (shouldWriteSeparatingLineTerminator(previousSibling, child, format)) { // If a synthesized node in a single-line list starts on a new // line, we should increase the indent. if ((format & (ListFormat.LinesMask | ListFormat.Indented)) === ListFormat.SingleLine) { increaseIndent(); shouldDecreaseIndentAfterEmit = true; } writeLine(); shouldEmitInterveningComments = false; } else if (previousSibling && format & ListFormat.SpaceBetweenSiblings) { write(" "); } } if (shouldEmitInterveningComments) { const commentRange = child.commentRange || child; emitTrailingCommentsOfPosition(commentRange.pos); } else { shouldEmitInterveningComments = mayEmitInterveningComments; } // Emit this child. emit(child); if (shouldDecreaseIndentAfterEmit) { decreaseIndent(); shouldDecreaseIndentAfterEmit = false; } previousSibling = child; } // Write a trailing comma, if requested. const hasTrailingComma = (format & ListFormat.AllowTrailingComma) && children.hasTrailingComma; if (format & ListFormat.CommaDelimited && hasTrailingComma) { write(","); } // Decrease the indent, if requested. if (format & ListFormat.Indented) { decreaseIndent(); } // Write the closing line terminator or closing whitespace. if (shouldWriteClosingLineTerminator(parentNode, children, format)) { writeLine(); } else if (format & ListFormat.SpaceBetweenBraces) { write(" "); } } if (format & ListFormat.BracketsMask) { write(getClosingBracket(format)); } } function writeIfAny(nodes: NodeArray, text: string) { if (nodes && nodes.length > 0) { write(text); } } function writeIfPresent(node: Node, text: string) { if (node !== undefined) { write(text); } } function writeToken(token: SyntaxKind, pos: number, contextNode?: Node) { const tokenStartPos = emitTokenStart(token, pos, contextNode, shouldSkipLeadingSourceMapForToken, getTokenSourceMapRange); const tokenEndPos = writeTokenText(token, tokenStartPos); return emitTokenEnd(token, tokenEndPos, contextNode, shouldSkipTrailingSourceMapForToken, getTokenSourceMapRange); } function shouldSkipLeadingSourceMapForToken(contextNode: Node) { return (contextNode.emitFlags & NodeEmitFlags.NoTokenLeadingSourceMaps) !== 0; } function shouldSkipTrailingSourceMapForToken(contextNode: Node) { return (contextNode.emitFlags & NodeEmitFlags.NoTokenTrailingSourceMaps) !== 0; } function writeTokenText(token: SyntaxKind, pos?: number) { const tokenString = tokenToString(token); write(tokenString); return positionIsSynthesized(pos) ? -1 : pos + tokenString.length; } function writeTokenNode(node: Node) { if (node) { emitStart(/*range*/ node, /*contextNode*/ node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); writeTokenText(node.kind); emitEnd(/*range*/ node, /*contextNode*/ node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); } } function increaseIndentIf(value: boolean, valueToWriteWhenNotIndenting?: string) { if (value) { increaseIndent(); writeLine(); } else if (valueToWriteWhenNotIndenting) { write(valueToWriteWhenNotIndenting); } } // 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: boolean, value2?: boolean) { if (value1) { decreaseIndent(); } if (value2) { decreaseIndent(); } } function shouldWriteLeadingLineTerminator(parentNode: Node, children: NodeArray, format: ListFormat) { if (format & ListFormat.MultiLine) { return true; } if (format & ListFormat.PreserveLines) { if (format & ListFormat.PreferNewLine) { return true; } const firstChild = children[0]; if (firstChild === undefined) { return !rangeIsOnSingleLine(parentNode, currentSourceFile); } else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(firstChild)) { return synthesizedNodeStartsOnNewLine(firstChild, format); } else { return !rangeStartPositionsAreOnSameLine(parentNode, firstChild, currentSourceFile); } } else { return false; } } function shouldWriteSeparatingLineTerminator(previousNode: Node, nextNode: Node, format: ListFormat) { if (format & ListFormat.MultiLine) { return true; } else if (format & ListFormat.PreserveLines) { if (previousNode === undefined || nextNode === undefined) { return false; } else if (nodeIsSynthesized(previousNode) || nodeIsSynthesized(nextNode)) { return synthesizedNodeStartsOnNewLine(previousNode, format) || synthesizedNodeStartsOnNewLine(nextNode, format); } else { return !rangeEndIsOnSameLineAsRangeStart(previousNode, nextNode, currentSourceFile); } } else { return nextNode.startsOnNewLine; } } function shouldWriteClosingLineTerminator(parentNode: Node, children: NodeArray, format: ListFormat) { if (format & ListFormat.MultiLine) { return (format & ListFormat.NoTrailingNewLine) === 0; } else if (format & ListFormat.PreserveLines) { if (format & ListFormat.PreferNewLine) { return true; } const lastChild = lastOrUndefined(children); if (lastChild === undefined) { return !rangeIsOnSingleLine(parentNode, currentSourceFile); } else if (positionIsSynthesized(parentNode.pos) || nodeIsSynthesized(lastChild)) { return synthesizedNodeStartsOnNewLine(lastChild, format); } else { return !rangeEndPositionsAreOnSameLine(parentNode, lastChild, currentSourceFile); } } else { return false; } } function synthesizedNodeStartsOnNewLine(node: Node, format?: ListFormat) { if (nodeIsSynthesized(node)) { const startsOnNewLine = node.startsOnNewLine; if (startsOnNewLine === undefined) { return (format & ListFormat.PreferNewLine) !== 0; } return startsOnNewLine; } return (format & ListFormat.PreferNewLine) !== 0; } function needsIndentation(parent: Node, node1: Node, node2: Node): boolean { parent = skipSynthesizedParentheses(parent); node1 = skipSynthesizedParentheses(node1); node2 = skipSynthesizedParentheses(node2); // Always use a newline for synthesized code if the synthesizer desires it. if (node2.startsOnNewLine) { return true; } return !nodeIsSynthesized(parent) && !nodeIsSynthesized(node1) && !nodeIsSynthesized(node2) && !rangeEndIsOnSameLineAsRangeStart(node1, node2, currentSourceFile); } function skipSynthesizedParentheses(node: Node) { while (node.kind === SyntaxKind.ParenthesizedExpression && nodeIsSynthesized(node)) { node = (node).expression; } return node; } function getTextOfNode(node: Node, includeTrivia?: boolean): string { if (isGeneratedIdentifier(node)) { return getGeneratedIdentifier(node); } else if (isIdentifier(node) && (nodeIsSynthesized(node) || !node.parent)) { return unescapeIdentifier(node.text); } else if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) { return getTextOfNode((node).textSourceNode, includeTrivia); } else if (isLiteralExpression(node) && (nodeIsSynthesized(node) || !node.parent)) { return node.text; } return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia); } function getLiteralTextOfNode(node: LiteralLikeNode): string { if (node.kind === SyntaxKind.StringLiteral && (node).textSourceNode) { const textSourceNode = (node).textSourceNode; if (isIdentifier(textSourceNode)) { return "\"" + escapeNonAsciiCharacters(escapeString(getTextOfNode(textSourceNode))) + "\""; } else { return getLiteralTextOfNode(textSourceNode); } } return getLiteralText(node, currentSourceFile, languageVersion); } function tryGetConstEnumValue(node: Node): number { if (compilerOptions.isolatedModules) { return undefined; } return isPropertyAccessExpression(node) || isElementAccessExpression(node) ? resolver.getConstantValue(node) : undefined; } function isSingleLineEmptyBlock(block: Block) { return !block.multiLine && block.statements.length === 0 && rangeEndIsOnSameLineAsRangeStart(block, block, currentSourceFile); } function isUniqueName(name: string): boolean { return !resolver.hasGlobalName(name) && !hasProperty(currentFileIdentifiers, name) && !hasProperty(generatedNameSet, name); } function isUniqueLocalName(name: string, container: Node): boolean { for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) { if (node.locals && hasProperty(node.locals, name)) { // We conservatively include alias symbols to cover cases where they're emitted as locals if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) { return false; } } } return true; } /** * 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: TempFlags): string { if (flags && !(tempFlags & flags)) { const name = flags === TempFlags._i ? "_i" : "_n"; if (isUniqueName(name)) { tempFlags |= flags; return name; } } while (true) { const count = tempFlags & TempFlags.CountMask; tempFlags++; // Skip over 'i' and 'n' if (count !== 8 && count !== 13) { const name = count < 26 ? "_" + String.fromCharCode(CharacterCodes.a + count) : "_" + (count - 26); if (isUniqueName(name)) { return name; } } } } // 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: string): string { // Find the first unique 'name_n', where n is a positive number if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) { baseName += "_"; } let i = 1; while (true) { const generatedName = baseName + i; if (isUniqueName(generatedName)) { return generatedNameSet[generatedName] = generatedName; } i++; } } function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { const name = getTextOfNode(node.name); // Use module/enum name itself if it is unique, otherwise make a unique variation return isUniqueLocalName(name, node) ? name : makeUniqueName(name); } function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { const expr = getExternalModuleName(node); const baseName = expr.kind === SyntaxKind.StringLiteral ? escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module"; return makeUniqueName(baseName); } function generateNameForExportDefault() { return makeUniqueName("default"); } function generateNameForClassExpression() { return makeUniqueName("class"); } /** * Generates a unique name from a node. * * @param node A node. */ function generateNameForNode(node: Node): string { switch (node.kind) { case SyntaxKind.Identifier: return makeUniqueName(getTextOfNode(node)); case SyntaxKind.ModuleDeclaration: case SyntaxKind.EnumDeclaration: return generateNameForModuleOrEnum(node); case SyntaxKind.ImportDeclaration: case SyntaxKind.ExportDeclaration: return generateNameForImportOrExportDeclaration(node); case SyntaxKind.FunctionDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.ExportAssignment: return generateNameForExportDefault(); case SyntaxKind.ClassExpression: return generateNameForClassExpression(); default: return makeTempVariableName(TempFlags.Auto); } } /** * Generates a unique identifier for a node. * * @param name A generated name. */ function generateName(name: Identifier) { switch (name.autoGenerateKind) { case GeneratedIdentifierKind.Auto: return makeTempVariableName(TempFlags.Auto); case GeneratedIdentifierKind.Loop: return makeTempVariableName(TempFlags._i); case GeneratedIdentifierKind.Unique: return makeUniqueName(name.text); } Debug.fail("Unsupported GeneratedIdentifierKind."); } /** * Gets the node from which a name should be generated. * * @param name A generated name wrapper. */ function getNodeForGeneratedName(name: Identifier) { const autoGenerateId = name.autoGenerateId; let node = name as Node; let original = node.original; while (original) { node = original; // if "node" is a different generated name (having a different // "autoGenerateId"), use it and stop traversing. if (isIdentifier(node) && node.autoGenerateKind === GeneratedIdentifierKind.Node && node.autoGenerateId !== autoGenerateId) { break; } original = node.original; } // otherwise, return the original node for the source; return node; } /** * Gets the generated identifier text from a generated identifier. * * @param name The generated identifier. */ function getGeneratedIdentifier(name: Identifier) { if (name.autoGenerateKind === GeneratedIdentifierKind.Node) { // Generated names generate unique names based on their original node // and are cached based on that node's id const node = getNodeForGeneratedName(name); const nodeId = getNodeId(node); return nodeIdToGeneratedName[nodeId] || (nodeIdToGeneratedName[nodeId] = unescapeIdentifier(generateNameForNode(node))); } else { // Auto, Loop, and Unique names are cached based on their unique // autoGenerateId. const autoGenerateId = name.autoGenerateId; return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = unescapeIdentifier(generateName(name))); } } function createDelimiterMap() { const delimiters: string[] = []; delimiters[ListFormat.None] = ""; delimiters[ListFormat.CommaDelimited] = ","; delimiters[ListFormat.BarDelimited] = " |"; delimiters[ListFormat.AmpersandDelimited] = " &"; return delimiters; } function getDelimiter(format: ListFormat) { return delimiters[format & ListFormat.DelimitersMask]; } function createBracketsMap() { const brackets: string[][] = []; brackets[ListFormat.Braces] = ["{", "}"]; brackets[ListFormat.Parenthesis] = ["(", ")"]; brackets[ListFormat.AngleBrackets] = ["<", ">"]; brackets[ListFormat.SquareBrackets] = ["[", "]"]; return brackets; } function getOpeningBracket(format: ListFormat) { return brackets[format & ListFormat.BracketsMask][0]; } function getClosingBracket(format: ListFormat) { return brackets[format & ListFormat.BracketsMask][1]; } } const enum ListFormat { None = 0, // Line separators SingleLine = 0, // Prints the list on a single line (default). MultiLine = 1 << 0, // Prints the list on multiple lines. PreserveLines = 1 << 1, // Prints the list using line preservation if possible. LinesMask = SingleLine | MultiLine | PreserveLines, // Delimiters NotDelimited = 0, // There is no delimiter between list items (default). BarDelimited = 1 << 2, // Each list item is space-and-bar (" |") delimited. AmpersandDelimited = 1 << 3, // Each list item is space-and-ampersand (" &") delimited. CommaDelimited = 1 << 4, // Each list item is comma (",") delimited. DelimitersMask = BarDelimited | AmpersandDelimited | CommaDelimited, AllowTrailingComma = 1 << 5, // Write a trailing comma (",") if present. // Whitespace Indented = 1 << 6, // The list should be indented. SpaceBetweenBraces = 1 << 7, // Inserts a space after the opening brace and before the closing brace. SpaceBetweenSiblings = 1 << 8, // Inserts a space between each sibling node. // Brackets/Braces Braces = 1 << 9, // The list is surrounded by "{" and "}". Parenthesis = 1 << 10, // The list is surrounded by "(" and ")". AngleBrackets = 1 << 11, // The list is surrounded by "<" and ">". SquareBrackets = 1 << 12, // The list is surrounded by "[" and "]". BracketsMask = Braces | Parenthesis | AngleBrackets | SquareBrackets, OptionalIfUndefined = 1 << 13, // Do not emit brackets if the list is undefined. OptionalIfEmpty = 1 << 14, // Do not emit brackets if the list is empty. Optional = OptionalIfUndefined | OptionalIfEmpty, // Other PreferNewLine = 1 << 15, // Prefer adding a LineTerminator between synthesized nodes. NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list. NoInterveningComments = 1 << 17, // Do not emit comments between each node // Precomputed Formats Modifiers = SingleLine | SpaceBetweenSiblings, HeritageClauses = SingleLine | SpaceBetweenSiblings, TypeLiteralMembers = MultiLine | Indented, TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented, UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine, IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine, ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings, ArrayBindingPatternElements = SingleLine | AllowTrailingComma | CommaDelimited | SpaceBetweenSiblings, ObjectLiteralExpressionProperties = PreserveLines | CommaDelimited | SpaceBetweenSiblings | SpaceBetweenBraces | Indented | Braces, ArrayLiteralExpressionElements = PreserveLines | CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | Indented | SquareBrackets, CallExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis, NewExpressionArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis | OptionalIfUndefined, TemplateExpressionSpans = SingleLine | NoInterveningComments, SingleLineBlockStatements = SpaceBetweenBraces | SpaceBetweenSiblings | SingleLine, MultiLineBlockStatements = Indented | MultiLine, VariableDeclarationList = CommaDelimited | SpaceBetweenSiblings | SingleLine, SingleLineFunctionBodyStatements = SingleLine | SpaceBetweenSiblings | SpaceBetweenBraces, MultiLineFunctionBodyStatements = MultiLine, ClassHeritageClauses = SingleLine | SpaceBetweenSiblings, ClassMembers = Indented | MultiLine, InterfaceMembers = Indented | MultiLine, EnumMembers = CommaDelimited | Indented | MultiLine, CaseBlockClauses = Indented | MultiLine, NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine | SpaceBetweenBraces, JsxElementChildren = SingleLine | NoInterveningComments, JsxElementAttributes = SingleLine | SpaceBetweenSiblings | NoInterveningComments, CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty, HeritageClauseTypes = CommaDelimited | SpaceBetweenSiblings | SingleLine, SourceFileStatements = MultiLine | NoTrailingNewLine, Decorators = MultiLine | Optional, TypeArguments = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | AngleBrackets | Optional, TypeParameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | AngleBrackets | Optional, Parameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | Parenthesis, IndexSignatureParameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | SquareBrackets, } }