diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index ed61d20610c1b..f8ceaf4610f51 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -246,6 +246,13 @@ namespace ts { } } + const enum PipelinePhase { + Notification, + Comments, + SourceMaps, + Emit + } + export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer { const { hasGlobalName, @@ -408,7 +415,9 @@ namespace ts { if (sourceFile) { setSourceFile(sourceFile); } - pipelineEmitWithNotification(hint, node); + + const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, hint); + pipelinePhase(hint, node); } function setSourceFile(sourceFile: SourceFile) { @@ -435,456 +444,452 @@ namespace ts { setWriter(/*output*/ undefined); } - // TODO: Should this just be `emit`? - // See https://github.com/Microsoft/TypeScript/pull/18284#discussion_r137611034 - function emitIfPresent(node: Node | undefined) { - if (node) { - emit(node); - } + function emit(node: Node | undefined) { + if (!node) return; + const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, EmitHint.Unspecified); + pipelinePhase(EmitHint.Unspecified, node); } - function emit(node: Node) { - pipelineEmitWithNotification(EmitHint.Unspecified, node); + function emitIdentifierName(node: Identifier | undefined) { + if (!node) return; + const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, EmitHint.IdentifierName); + pipelinePhase(EmitHint.IdentifierName, node); } - function emitIdentifierName(node: Identifier) { - pipelineEmitWithNotification(EmitHint.IdentifierName, node); + function emitExpression(node: Expression | undefined) { + if (!node) return; + const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, EmitHint.Expression); + pipelinePhase(EmitHint.Expression, node); + } + + function getPipelinePhase(phase: PipelinePhase, hint: EmitHint) { + switch (phase) { + case PipelinePhase.Notification: + if (onEmitNode) { + return pipelineEmitWithNotification; + } + // falls through + + case PipelinePhase.Comments: + if (emitNodeWithComments && hint !== EmitHint.SourceFile) { + return pipelineEmitWithComments; + } + return pipelineEmitWithoutComments; + + case PipelinePhase.SourceMaps: + if (onEmitSourceMapOfNode && hint !== EmitHint.SourceFile && hint !== EmitHint.IdentifierName) { + return pipelineEmitWithSourceMap; + } + // falls through + + case PipelinePhase.Emit: + return pipelineEmitWithHint; + + default: + return Debug.assertNever(phase, `Unexpected value for PipelinePhase: ${phase}`); + } } - function emitExpression(node: Expression) { - pipelineEmitWithNotification(EmitHint.Expression, node); + function getNextPipelinePhase(currentPhase: PipelinePhase, hint: EmitHint) { + return getPipelinePhase(currentPhase + 1, hint); } function pipelineEmitWithNotification(hint: EmitHint, node: Node) { - if (onEmitNode) { - onEmitNode(hint, node, pipelineEmitWithComments); - } - else { - pipelineEmitWithComments(hint, node); - } + Debug.assertDefined(onEmitNode); + onEmitNode(hint, node, getNextPipelinePhase(PipelinePhase.Notification, hint)); } function pipelineEmitWithComments(hint: EmitHint, node: Node) { - node = trySubstituteNode(hint, node); - if (emitNodeWithComments && hint !== EmitHint.SourceFile) { - emitNodeWithComments(hint, node, pipelineEmitWithSourceMap); - } - else { - pipelineEmitWithSourceMap(hint, node); - } + Debug.assertDefined(emitNodeWithComments); + Debug.assert(hint !== EmitHint.SourceFile); + emitNodeWithComments(hint, trySubstituteNode(hint, node), getNextPipelinePhase(PipelinePhase.Comments, hint)); + } + + function pipelineEmitWithoutComments(hint: EmitHint, node: Node) { + const pipelinePhase = getNextPipelinePhase(PipelinePhase.Comments, hint); + pipelinePhase(hint, trySubstituteNode(hint, node)); } function pipelineEmitWithSourceMap(hint: EmitHint, node: Node) { - if (onEmitSourceMapOfNode && hint !== EmitHint.SourceFile && hint !== EmitHint.IdentifierName) { - onEmitSourceMapOfNode(hint, node, pipelineEmitWithHint); - } - else { - pipelineEmitWithHint(hint, node); - } + Debug.assertDefined(onEmitSourceMapOfNode); + Debug.assert(hint !== EmitHint.SourceFile && hint !== EmitHint.IdentifierName); + onEmitSourceMapOfNode(hint, node, pipelineEmitWithHint); } function pipelineEmitWithHint(hint: EmitHint, node: Node): void { - switch (hint) { - case EmitHint.SourceFile: return pipelineEmitSourceFile(node); - case EmitHint.IdentifierName: return pipelineEmitIdentifierName(node); - case EmitHint.Expression: return pipelineEmitExpression(node); - case EmitHint.MappedTypeParameter: return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); - case EmitHint.Unspecified: return pipelineEmitUnspecified(node); + if (hint === EmitHint.SourceFile) return emitSourceFile(cast(node, isSourceFile)); + if (hint === EmitHint.IdentifierName) return emitIdentifier(cast(node, isIdentifier)); + if (hint === EmitHint.MappedTypeParameter) return emitMappedTypeParameter(cast(node, isTypeParameterDeclaration)); + if (hint === EmitHint.Unspecified) { + if (isKeyword(node.kind)) return writeTokenNode(node, writeKeyword); + + switch (node.kind) { + // Pseudo-literals + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + return emitLiteral(node); + + // Identifiers + case SyntaxKind.Identifier: + return emitIdentifier(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.JSDocFunctionType: + return emitJSDocFunctionType(node as JSDocFunctionType); + 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.ConditionalType: + return emitConditionalType(node); + case SyntaxKind.InferType: + return emitInferType(node); + case SyntaxKind.ParenthesizedType: + return emitParenthesizedType(node); + case SyntaxKind.ExpressionWithTypeArguments: + return emitExpressionWithTypeArguments(node); + case SyntaxKind.ThisType: + return emitThisType(); + case SyntaxKind.TypeOperator: + return emitTypeOperator(node); + case SyntaxKind.IndexedAccessType: + return emitIndexedAccessType(node); + case SyntaxKind.MappedType: + return emitMappedType(node); + case SyntaxKind.LiteralType: + return emitLiteralType(node); + case SyntaxKind.ImportType: + return emitImportTypeNode(node); + case SyntaxKind.JSDocAllType: + write("*"); + return; + case SyntaxKind.JSDocUnknownType: + write("?"); + return; + case SyntaxKind.JSDocNullableType: + return emitJSDocNullableType(node as JSDocNullableType); + case SyntaxKind.JSDocNonNullableType: + return emitJSDocNonNullableType(node as JSDocNonNullableType); + case SyntaxKind.JSDocOptionalType: + return emitJSDocOptionalType(node as JSDocOptionalType); + case SyntaxKind.JSDocVariadicType: + return emitJSDocVariadicType(node as JSDocVariadicType); + + // 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(); + + // Statements + case SyntaxKind.Block: + return emitBlock(node); + case SyntaxKind.VariableStatement: + return emitVariableStatement(node); + case SyntaxKind.EmptyStatement: + return emitEmptyStatement(); + 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.NamespaceExportDeclaration: + return emitNamespaceExportDeclaration(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: + case SyntaxKind.JsxOpeningFragment: + return emitJsxOpeningElementOrFragment(node); + case SyntaxKind.JsxClosingElement: + case SyntaxKind.JsxClosingFragment: + return emitJsxClosingElementOrFragment(node); + case SyntaxKind.JsxAttribute: + return emitJsxAttribute(node); + case SyntaxKind.JsxAttributes: + return emitJsxAttributes(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); + case SyntaxKind.SpreadAssignment: + return emitSpreadAssignment(node as SpreadAssignment); + + // Enum + case SyntaxKind.EnumMember: + return emitEnumMember(node); + + // JSDoc nodes (ignored) + // Transformation nodes (ignored) + } + + if (isExpression(node)) { + hint = EmitHint.Expression; + node = trySubstituteNode(EmitHint.Expression, node); + } + else if (isToken(node)) { + return writeTokenNode(node, writePunctuation); + } + } + if (hint === EmitHint.Expression) { + switch (node.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: + case SyntaxKind.ImportKeyword: + writeTokenNode(node, writeKeyword); + return; + + // 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.SpreadElement: + return emitSpreadExpression(node); + case SyntaxKind.ClassExpression: + return emitClassExpression(node); + case SyntaxKind.OmittedExpression: + return; + case SyntaxKind.AsExpression: + return emitAsExpression(node); + case SyntaxKind.NonNullExpression: + return emitNonNullExpression(node); + case SyntaxKind.MetaProperty: + return emitMetaProperty(node); + + // JSX + case SyntaxKind.JsxElement: + return emitJsxElement(node); + case SyntaxKind.JsxSelfClosingElement: + return emitJsxSelfClosingElement(node); + case SyntaxKind.JsxFragment: + return emitJsxFragment(node); + + // Transformation nodes + case SyntaxKind.PartiallyEmittedExpression: + return emitPartiallyEmittedExpression(node); + + case SyntaxKind.CommaListExpression: + return emitCommaList(node); + } } } - function pipelineEmitSourceFile(node: Node): void { - Debug.assertNode(node, isSourceFile); - emitSourceFile(node); - } - - function pipelineEmitIdentifierName(node: Node): void { - Debug.assertNode(node, isIdentifier); - emitIdentifier(node); - } - function emitMappedTypeParameter(node: TypeParameterDeclaration): void { emit(node.name); writeSpace(); writeKeyword("in"); writeSpace(); - emitIfPresent(node.constraint); - } - - function pipelineEmitUnspecified(node: Node): void { - const kind = node.kind; - - // Reserved words - // Strict mode reserved words - // Contextual keywords - if (isKeyword(kind)) { - writeTokenNode(node, writeKeyword); - return; - } - - switch (kind) { - // Pseudo-literals - case SyntaxKind.TemplateHead: - case SyntaxKind.TemplateMiddle: - case SyntaxKind.TemplateTail: - return emitLiteral(node); - - // Identifiers - case SyntaxKind.Identifier: - return emitIdentifier(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.JSDocFunctionType: - return emitJSDocFunctionType(node as JSDocFunctionType); - 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.ConditionalType: - return emitConditionalType(node); - case SyntaxKind.InferType: - return emitInferType(node); - case SyntaxKind.ParenthesizedType: - return emitParenthesizedType(node); - case SyntaxKind.ExpressionWithTypeArguments: - return emitExpressionWithTypeArguments(node); - case SyntaxKind.ThisType: - return emitThisType(); - case SyntaxKind.TypeOperator: - return emitTypeOperator(node); - case SyntaxKind.IndexedAccessType: - return emitIndexedAccessType(node); - case SyntaxKind.MappedType: - return emitMappedType(node); - case SyntaxKind.LiteralType: - return emitLiteralType(node); - case SyntaxKind.ImportType: - return emitImportTypeNode(node); - case SyntaxKind.JSDocAllType: - write("*"); - return; - case SyntaxKind.JSDocUnknownType: - write("?"); - return; - case SyntaxKind.JSDocNullableType: - return emitJSDocNullableType(node as JSDocNullableType); - case SyntaxKind.JSDocNonNullableType: - return emitJSDocNonNullableType(node as JSDocNonNullableType); - case SyntaxKind.JSDocOptionalType: - return emitJSDocOptionalType(node as JSDocOptionalType); - case SyntaxKind.JSDocVariadicType: - return emitJSDocVariadicType(node as JSDocVariadicType); - - // 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(); - - // Statements - case SyntaxKind.Block: - return emitBlock(node); - case SyntaxKind.VariableStatement: - return emitVariableStatement(node); - case SyntaxKind.EmptyStatement: - return emitEmptyStatement(); - 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.NamespaceExportDeclaration: - return emitNamespaceExportDeclaration(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: - case SyntaxKind.JsxOpeningFragment: - return emitJsxOpeningElementOrFragment(node); - case SyntaxKind.JsxClosingElement: - case SyntaxKind.JsxClosingFragment: - return emitJsxClosingElementOrFragment(node); - case SyntaxKind.JsxAttribute: - return emitJsxAttribute(node); - case SyntaxKind.JsxAttributes: - return emitJsxAttributes(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); - case SyntaxKind.SpreadAssignment: - return emitSpreadAssignment(node as SpreadAssignment); - - // Enum - case SyntaxKind.EnumMember: - return emitEnumMember(node); - - // JSDoc nodes (ignored) - // Transformation nodes (ignored) - } - - // If the node is an expression, try to emit it as an expression with - // substitution. - if (isExpression(node)) { - return pipelineEmitExpression(trySubstituteNode(EmitHint.Expression, node)); - } - - if (isToken(node)) { - writeTokenNode(node, writePunctuation); - return; - } - } - - function pipelineEmitExpression(node: Node): void { - 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: - case SyntaxKind.ImportKeyword: - writeTokenNode(node, writeKeyword); - return; - - // 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.SpreadElement: - return emitSpreadExpression(node); - case SyntaxKind.ClassExpression: - return emitClassExpression(node); - case SyntaxKind.OmittedExpression: - return; - case SyntaxKind.AsExpression: - return emitAsExpression(node); - case SyntaxKind.NonNullExpression: - return emitNonNullExpression(node); - case SyntaxKind.MetaProperty: - return emitMetaProperty(node); - - // JSX - case SyntaxKind.JsxElement: - return emitJsxElement(node); - case SyntaxKind.JsxSelfClosingElement: - return emitJsxSelfClosingElement(node); - case SyntaxKind.JsxFragment: - return emitJsxFragment(node); - - // Transformation nodes - case SyntaxKind.PartiallyEmittedExpression: - return emitPartiallyEmittedExpression(node); - - case SyntaxKind.CommaListExpression: - return emitCommaList(node); - } + emit(node.constraint); } function trySubstituteNode(hint: EmitHint, node: Node) { @@ -1027,13 +1032,11 @@ namespace ts { function emitParameter(node: ParameterDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); - emitIfPresent(node.dotDotDotToken); - if (node.name) { - emitNodeWithWriter(node.name, writeParameter); - } - emitIfPresent(node.questionToken); + emit(node.dotDotDotToken); + emitNodeWithWriter(node.name, writeParameter); + emit(node.questionToken); if (node.parent && node.parent.kind === SyntaxKind.JSDocFunctionType && !node.name) { - emitIfPresent(node.type); + emit(node.type); } else { emitTypeAnnotation(node.type); @@ -1055,7 +1058,7 @@ namespace ts { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emitNodeWithWriter(node.name, writeProperty); - emitIfPresent(node.questionToken); + emit(node.questionToken); emitTypeAnnotation(node.type); writeSemicolon(); } @@ -1064,8 +1067,8 @@ namespace ts { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emit(node.name); - emitIfPresent(node.questionToken); - emitIfPresent(node.exclamationToken); + emit(node.questionToken); + emit(node.exclamationToken); emitTypeAnnotation(node.type); emitInitializer(node.initializer, node.type ? node.type.end : node.questionToken ? node.questionToken.end : node.name.end, node); writeSemicolon(); @@ -1075,7 +1078,7 @@ namespace ts { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); emit(node.name); - emitIfPresent(node.questionToken); + emit(node.questionToken); emitTypeParameters(node, node.typeParameters); emitParameters(node, node.parameters); emitTypeAnnotation(node.type); @@ -1085,9 +1088,9 @@ namespace ts { function emitMethodDeclaration(node: MethodDeclaration) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); - emitIfPresent(node.asteriskToken); + emit(node.asteriskToken); emit(node.name); - emitIfPresent(node.questionToken); + emit(node.questionToken); emitSignatureAndBody(node, emitSignatureHead); } @@ -1161,14 +1164,14 @@ namespace ts { writeSpace(); writePunctuation("=>"); writeSpace(); - emitIfPresent(node.type); + emit(node.type); } function emitJSDocFunctionType(node: JSDocFunctionType) { write("function"); emitParameters(node, node.parameters); write(":"); - emitIfPresent(node.type); + emit(node.type); } @@ -1195,7 +1198,7 @@ namespace ts { writeSpace(); writePunctuation("=>"); writeSpace(); - emitIfPresent(node.type); + emit(node.type); } function emitTypeQuery(node: TypeQueryNode) { @@ -1299,7 +1302,10 @@ namespace ts { writeSpace(); } writePunctuation("["); - pipelineEmitWithNotification(EmitHint.MappedTypeParameter, node.typeParameter); + + const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, EmitHint.MappedTypeParameter); + pipelinePhase(EmitHint.MappedTypeParameter, node.typeParameter); + writePunctuation("]"); if (node.questionToken) { emit(node.questionToken); @@ -1309,7 +1315,7 @@ namespace ts { } writePunctuation(":"); writeSpace(); - emitIfPresent(node.type); + emit(node.type); writeSemicolon(); if (emitFlags & EmitFlags.SingleLine) { writeSpace(); @@ -1358,7 +1364,7 @@ namespace ts { } function emitBindingElement(node: BindingElement) { - emitIfPresent(node.dotDotDotToken); + emit(node.dotDotDotToken); if (node.propertyName) { emit(node.propertyName); writePunctuation(":"); @@ -1600,7 +1606,7 @@ namespace ts { function emitYieldExpression(node: YieldExpression) { emitTokenWithComment(SyntaxKind.YieldKeyword, node.pos, writeKeyword, node); - emitIfPresent(node.asteriskToken); + emit(node.asteriskToken); emitExpressionWithLeadingSpace(node.expression); } @@ -1896,7 +1902,7 @@ namespace ts { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); writeKeyword("function"); - emitIfPresent(node.asteriskToken); + emit(node.asteriskToken); writeSpace(); emitIdentifierName(node.name); emitSignatureAndBody(node, emitSignatureHead); @@ -2170,12 +2176,12 @@ namespace ts { } function emitImportClause(node: ImportClause) { - emitIfPresent(node.name); + emit(node.name); if (node.name && node.namedBindings) { emitTokenWithComment(SyntaxKind.CommaToken, node.name.end, writePunctuation, node); writeSpace(); } - emitIfPresent(node.namedBindings); + emit(node.namedBindings); } function emitNamespaceImport(node: NamespaceImport) { @@ -2343,7 +2349,7 @@ namespace ts { function emitJsxExpression(node: JsxExpression) { if (node.expression) { writePunctuation("{"); - emitIfPresent(node.dotDotDotToken); + emit(node.dotDotDotToken); emitExpression(node.expression); writePunctuation("}"); } @@ -2610,7 +2616,8 @@ namespace ts { // Helpers // - function emitNodeWithWriter(node: Node, writer: typeof write) { + function emitNodeWithWriter(node: Node | undefined, writer: typeof write) { + if (!node) return; const savedWrite = write; write = writer; emit(node);