From 4652f053b1d975aa1a18a22c2d7882d13ea1679b Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 15 Jul 2015 12:13:34 -0700 Subject: [PATCH] Partial transform for class decorators --- scripts/processTypes.ts | 2 +- src/compiler/binder.ts | 5 +- src/compiler/emitter.ts | 9 +- src/compiler/factory.generated.ts | 57 ++-- src/compiler/factory.ts | 34 ++- src/compiler/parser.ts | 8 +- src/compiler/transform.generated.ts | 69 ++--- src/compiler/transform.ts | 96 ++++++- src/compiler/transforms/es6.ts | 428 ++++++++++++++++++++++++++-- src/compiler/types.ts | 22 +- src/compiler/utilities.ts | 11 +- 11 files changed, 642 insertions(+), 99 deletions(-) diff --git a/scripts/processTypes.ts b/scripts/processTypes.ts index fa9c35c1d48..9f91ef3749d 100644 --- a/scripts/processTypes.ts +++ b/scripts/processTypes.ts @@ -802,7 +802,7 @@ function generateTransform(outputFile: string) { return; } - writer.write(`export function visitNodeArrayOf${typeNameToMethodNameSuffix(typeName)}(context: VisitorContext, nodes: NodeArray<${typeName}>, visitor: Visitor): NodeArray<${typeName}> {`); + writer.write(`export function visitNodeArrayOf${typeNameToMethodNameSuffix(typeName)}(context: VisitorContext, nodes: Array<${typeName}>, visitor: Visitor): NodeArray<${typeName}> {`); writer.writeLine(); writer.increaseIndent(); diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index e839d6d6c9a..e956bac860e 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -854,8 +854,9 @@ namespace ts { case SyntaxKind.BindingElement: return bindVariableDeclarationOrBindingElement(node); case SyntaxKind.PropertyDeclaration: + return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); case SyntaxKind.PropertySignature: - return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes); + return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : SymbolFlags.None), SymbolFlags.PropertyExcludes); case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: return bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); @@ -1056,4 +1057,4 @@ namespace ts { : declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes); } } -} +} diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 8b63336e83f..57c5bb9f017 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -304,6 +304,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi return generateNameForExportDefault(); case SyntaxKind.ClassExpression: return generateNameForClassExpression(); + case SyntaxKind.ComputedPropertyName: + return makeTempVariableName(TempFlags.Auto); } } @@ -4297,7 +4299,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi write(")"); } else { - writeLine(); + if (!isClassExpression(node)) { + writeLine(); + } + emitPropertyDeclarations(node, staticProperties); emitDecoratorsOfClass(node); } @@ -6122,7 +6127,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // Process tree transformations let statements = node.statements; if (compilerOptions.experimentalTransforms) { - let context = new transform.VisitorContext(currentSourceFile, resolver, generatedNameSet, getGeneratedNameForNode); + let context = new transform.VisitorContext(compilerOptions, currentSourceFile, resolver, generatedNameSet, nodeToGeneratedName); statements = transformationChain(context, node.statements); } diff --git a/src/compiler/factory.generated.ts b/src/compiler/factory.generated.ts index a6b9c8068aa..fe000b18f17 100644 --- a/src/compiler/factory.generated.ts +++ b/src/compiler/factory.generated.ts @@ -130,7 +130,7 @@ namespace ts { } return node; } - export function createPropertySignature(decorators?: Array, modifiers?: Array, name?: DeclarationName, questionToken?: Node, + export function createPropertySignature(decorators?: Array, modifiers?: Array, name?: PropertyName, questionToken?: Node, type?: TypeNode, location?: TextRange, flags?: NodeFlags): PropertySignature { let node = createNode(SyntaxKind.PropertySignature, location, flags); if (arguments.length) { @@ -142,7 +142,7 @@ namespace ts { } return node; } - export function updatePropertySignature(node: PropertySignature, decorators: Array, modifiers: Array, name: DeclarationName + export function updatePropertySignature(node: PropertySignature, decorators: Array, modifiers: Array, name: PropertyName , type: TypeNode): PropertySignature { if (decorators !== node.decorators || modifiers !== node.modifiers || name !== node.name || type !== node.type) { let newNode = createPropertySignature(decorators, modifiers, name, node.questionToken, type); @@ -150,29 +150,28 @@ namespace ts { } return node; } - export function createPropertyDeclaration(decorators?: Array, modifiers?: Array, name?: DeclarationName, - questionToken?: Node, type?: TypeNode, initializer?: Expression, location?: TextRange, flags?: NodeFlags): PropertyDeclaration { + export function createPropertyDeclaration(decorators?: Array, modifiers?: Array, name?: PropertyName, type?: TypeNode, + initializer?: Expression, location?: TextRange, flags?: NodeFlags): PropertyDeclaration { let node = createNode(SyntaxKind.PropertyDeclaration, location, flags); if (arguments.length) { node.decorators = decorators && createNodeArray(decorators) setModifiers(node, modifiers); node.name = name; - node.questionToken = questionToken; node.type = type; node.initializer = initializer; } return node; } - export function updatePropertyDeclaration(node: PropertyDeclaration, decorators: Array, modifiers: Array - , name: DeclarationName, type: TypeNode, initializer: Expression): PropertyDeclaration { + export function updatePropertyDeclaration(node: PropertyDeclaration, decorators: Array, modifiers: Array, name: PropertyName + , type: TypeNode, initializer: Expression): PropertyDeclaration { if (decorators !== node.decorators || modifiers !== node.modifiers || name !== node.name || type !== node.type || initializer !== node.initializer) { - let newNode = createPropertyDeclaration(decorators, modifiers, name, node.questionToken, type, initializer); + let newNode = createPropertyDeclaration(decorators, modifiers, name, type, initializer); return updateFrom(node, newNode); } return node; } - export function createMethodSignature(decorators?: Array, modifiers?: Array, name?: DeclarationName, questionToken?: Node, + export function createMethodSignature(decorators?: Array, modifiers?: Array, name?: PropertyName, questionToken?: Node, typeParameters?: Array, parameters?: Array, type?: TypeNode, location?: TextRange, flags?: NodeFlags): MethodSignature { let node = createNode(SyntaxKind.MethodSignature, location, flags); @@ -187,7 +186,7 @@ namespace ts { } return node; } - export function updateMethodSignature(node: MethodSignature, decorators: Array, modifiers: Array, name: DeclarationName + export function updateMethodSignature(node: MethodSignature, decorators: Array, modifiers: Array, name: PropertyName , typeParameters: Array, parameters: Array, type: TypeNode): MethodSignature { if (decorators !== node.decorators || modifiers !== node.modifiers || name !== node.name || typeParameters !== node.typeParameters || parameters !== node.parameters || type !== node.type) { @@ -196,7 +195,7 @@ namespace ts { } return node; } - export function createMethodDeclaration(decorators?: Array, modifiers?: Array, asteriskToken?: Node, name?: DeclarationName, + export function createMethodDeclaration(decorators?: Array, modifiers?: Array, asteriskToken?: Node, name?: PropertyName, typeParameters?: Array, parameters?: Array, type?: TypeNode, body?: Block, location?: TextRange, flags?: NodeFlags): MethodDeclaration { let node = createNode(SyntaxKind.MethodDeclaration, location, flags); @@ -212,7 +211,7 @@ namespace ts { } return node; } - export function updateMethodDeclaration(node: MethodDeclaration, decorators: Array, modifiers: Array, name: DeclarationName + export function updateMethodDeclaration(node: MethodDeclaration, decorators: Array, modifiers: Array, name: PropertyName , typeParameters: Array, parameters: Array, type: TypeNode, body: Block ): MethodDeclaration { if (decorators !== node.decorators || modifiers !== node.modifiers || name !== node.name || typeParameters !== node.typeParameters || @@ -243,7 +242,7 @@ namespace ts { } return node; } - export function createGetAccessor(decorators?: Array, modifiers?: Array, name?: DeclarationName, + export function createGetAccessor(decorators?: Array, modifiers?: Array, name?: PropertyName, parameters?: Array, type?: TypeNode, body?: Block, location?: TextRange, flags?: NodeFlags): GetAccessorDeclaration { let node = createNode(SyntaxKind.GetAccessor, location, flags); @@ -257,7 +256,7 @@ namespace ts { } return node; } - export function updateGetAccessor(node: GetAccessorDeclaration, decorators: Array, modifiers: Array, name: DeclarationName + export function updateGetAccessor(node: GetAccessorDeclaration, decorators: Array, modifiers: Array, name: PropertyName , parameters: Array, type: TypeNode, body: Block): GetAccessorDeclaration { if (decorators !== node.decorators || modifiers !== node.modifiers || name !== node.name || parameters !== node.parameters || type !== node.type || body !== node.body) { @@ -266,7 +265,7 @@ namespace ts { } return node; } - export function createSetAccessor(decorators?: Array, modifiers?: Array, name?: DeclarationName, + export function createSetAccessor(decorators?: Array, modifiers?: Array, name?: PropertyName, parameters?: Array, type?: TypeNode, body?: Block, location?: TextRange, flags?: NodeFlags): SetAccessorDeclaration { let node = createNode(SyntaxKind.SetAccessor, location, flags); @@ -280,7 +279,7 @@ namespace ts { } return node; } - export function updateSetAccessor(node: SetAccessorDeclaration, decorators: Array, modifiers: Array, name: DeclarationName + export function updateSetAccessor(node: SetAccessorDeclaration, decorators: Array, modifiers: Array, name: PropertyName , parameters: Array, type: TypeNode, body: Block): SetAccessorDeclaration { if (decorators !== node.decorators || modifiers !== node.modifiers || name !== node.name || parameters !== node.parameters || type !== node.type || body !== node.body) { @@ -1788,7 +1787,7 @@ namespace ts { } return node; } - export function createPropertyAssignment(name?: DeclarationName, questionToken?: Node, initializer?: Expression, + export function createPropertyAssignment(name?: PropertyName, questionToken?: Node, initializer?: Expression, location?: TextRange, flags?: NodeFlags): PropertyAssignment { let node = createNode(SyntaxKind.PropertyAssignment, location, flags); if (arguments.length) { @@ -1798,7 +1797,7 @@ namespace ts { } return node; } - export function updatePropertyAssignment(node: PropertyAssignment, name: DeclarationName, initializer: Expression): PropertyAssignment { + export function updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression): PropertyAssignment { if (name !== node.name || initializer !== node.initializer) { let newNode = createPropertyAssignment(name, node.questionToken, initializer); return updateFrom(node, newNode); @@ -2165,8 +2164,8 @@ namespace ts { (node).name, (node).questionToken, (node).type, location, flags); case SyntaxKind.PropertyDeclaration: return factory.createPropertyDeclaration((node).decorators, (node).modifiers, - (node).name, (node).questionToken, (node).type, - (node).initializer, location, flags); + (node).name, (node).type, (node).initializer, + location, flags); case SyntaxKind.MethodSignature: return factory.createMethodSignature((node).decorators, (node).modifiers, (node).name, (node).questionToken, (node).typeParameters, @@ -3128,13 +3127,29 @@ namespace ts { } return false; } + export function isPropertyName(node: Node): node is PropertyName { + if (node) { + switch (node.kind) { + case SyntaxKind.Identifier: + case SyntaxKind.NumericLiteral: + case SyntaxKind.RegularExpressionLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: + case SyntaxKind.StringLiteral: + case SyntaxKind.ComputedPropertyName: + return true; + } + } + return false; + } export function isTypeElement(node: Node): node is TypeElement { if (node) { switch (node.kind) { case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: case SyntaxKind.PropertySignature: - case SyntaxKind.PropertyDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.IndexSignature: case SyntaxKind.MissingDeclaration: diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 309c7d88c94..7c47fd111c8 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -233,9 +233,9 @@ namespace ts { return factory.createVariableStatement( factory.createVariableDeclarationList([ factory.createVariableDeclaration2(name, initializer) - ]), + ], /*location*/ undefined, flags & (NodeFlags.Let | NodeFlags.Const)), location, - flags + flags & ~(NodeFlags.Let | NodeFlags.Const) ); } @@ -251,6 +251,36 @@ namespace ts { ); } + export function createClassDeclaration2(modifiers: Modifier[], name: Identifier, heritageClause: HeritageClause, members: ClassElement[]): ClassDeclaration { + return factory.createClassDeclaration( + /*decorators*/ undefined, + modifiers, + name, + /*typeParameters*/ undefined, + heritageClause ? [heritageClause] : undefined, + members + ); + } + + export function createClassExpression2(name: Identifier, heritageClause: HeritageClause, members: ClassElement[]): ClassExpression { + return factory.createClassExpression( + /*decorators*/ undefined, + /*modifiers*/ undefined, + name, + /*typeParameters*/ undefined, + heritageClause ? [heritageClause] : undefined, + members + ); + } + + export function createClassExpression3(heritageClause: HeritageClause, members: ClassElement[]) { + return factory.createClassExpression2( + /*name*/ undefined, + heritageClause, + members + ); + } + export function createFunctionDeclaration2(name: Identifier, parameters: ParameterDeclaration[], body: Block, location?: TextRange, flags?: NodeFlags) { return factory.createFunctionDeclaration( /*decorators*/ undefined, diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 899187d5cff..3371a4bcdf5 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1054,7 +1054,7 @@ namespace ts { token === SyntaxKind.NumericLiteral; } - function parsePropertyNameWorker(allowComputedPropertyNames: boolean): DeclarationName { + function parsePropertyNameWorker(allowComputedPropertyNames: boolean): PropertyName { if (token === SyntaxKind.StringLiteral || token === SyntaxKind.NumericLiteral) { return parseLiteralNode(/*internName*/ true); } @@ -1064,7 +1064,7 @@ namespace ts { return parseIdentifierName(); } - function parsePropertyName(): DeclarationName { + function parsePropertyName(): PropertyName { return parsePropertyNameWorker(/*allowComputedPropertyNames:*/ true); } @@ -4499,7 +4499,7 @@ namespace ts { return finishNode(node); } - function parseMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, asteriskToken: Node, name: DeclarationName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { + function parseMethodDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, asteriskToken: Node, name: PropertyName, questionToken: Node, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { let method = beginNode(factory.createMethodDeclaration(), fullStart); method.decorators = decorators; setModifiers(method, modifiers); @@ -4513,7 +4513,7 @@ namespace ts { return finishNode(method); } - function parsePropertyDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, name: DeclarationName, questionToken: Node): ClassElement { + function parsePropertyDeclaration(fullStart: number, decorators: NodeArray, modifiers: ModifiersArray, name: PropertyName, questionToken: Node): ClassElement { let property = beginNode(factory.createPropertyDeclaration(), fullStart); property.decorators = decorators; setModifiers(property, modifiers); diff --git a/src/compiler/transform.generated.ts b/src/compiler/transform.generated.ts index 57b3f3fb46c..2fa1c993f2e 100644 --- a/src/compiler/transform.generated.ts +++ b/src/compiler/transform.generated.ts @@ -40,14 +40,14 @@ namespace ts.transform { node, visitNodeArrayOfDecorator(context, (node).decorators, visitor), visitNodeArrayOfModifier(context, (node).modifiers, visitor), - visitDeclarationName(context, (node).name, visitor), + visitPropertyName(context, (node).name, visitor), visitTypeNode(context, (node).type, visitor)); case SyntaxKind.PropertyDeclaration: return factory.updatePropertyDeclaration( node, visitNodeArrayOfDecorator(context, (node).decorators, visitor), visitNodeArrayOfModifier(context, (node).modifiers, visitor), - visitDeclarationName(context, (node).name, visitor), + visitPropertyName(context, (node).name, visitor), visitTypeNode(context, (node).type, visitor), visitExpression(context, (node).initializer, visitor)); case SyntaxKind.MethodSignature: @@ -55,7 +55,7 @@ namespace ts.transform { node, visitNodeArrayOfDecorator(context, (node).decorators, visitor), visitNodeArrayOfModifier(context, (node).modifiers, visitor), - visitDeclarationName(context, (node).name, visitor), + visitPropertyName(context, (node).name, visitor), visitNodeArrayOfTypeParameter(context, (node).typeParameters, visitor), visitNodeArrayOfParameter(context, (node).parameters, visitor), visitTypeNode(context, (node).type, visitor)); @@ -64,7 +64,7 @@ namespace ts.transform { node, visitNodeArrayOfDecorator(context, (node).decorators, visitor), visitNodeArrayOfModifier(context, (node).modifiers, visitor), - visitDeclarationName(context, (node).name, visitor), + visitPropertyName(context, (node).name, visitor), visitNodeArrayOfTypeParameter(context, (node).typeParameters, visitor), visitNodeArrayOfParameter(context, (node).parameters, visitor), visitTypeNode(context, (node).type, visitor), @@ -82,7 +82,7 @@ namespace ts.transform { node, visitNodeArrayOfDecorator(context, (node).decorators, visitor), visitNodeArrayOfModifier(context, (node).modifiers, visitor), - visitDeclarationName(context, (node).name, visitor), + visitPropertyName(context, (node).name, visitor), visitNodeArrayOfParameter(context, (node).parameters, visitor), visitTypeNode(context, (node).type, visitor), visitBlockInNewLexicalScope(context, (node).body, visitor)); @@ -91,7 +91,7 @@ namespace ts.transform { node, visitNodeArrayOfDecorator(context, (node).decorators, visitor), visitNodeArrayOfModifier(context, (node).modifiers, visitor), - visitDeclarationName(context, (node).name, visitor), + visitPropertyName(context, (node).name, visitor), visitNodeArrayOfParameter(context, (node).parameters, visitor), visitTypeNode(context, (node).type, visitor), visitBlockInNewLexicalScope(context, (node).body, visitor)); @@ -588,7 +588,7 @@ namespace ts.transform { case SyntaxKind.PropertyAssignment: return factory.updatePropertyAssignment( node, - visitDeclarationName(context, (node).name, visitor), + visitPropertyName(context, (node).name, visitor), visitExpression(context, (node).initializer, visitor)); case SyntaxKind.ShorthandPropertyAssignment: return factory.updateShorthandPropertyAssignment( @@ -747,10 +747,10 @@ namespace ts.transform { Debug.assert(!visited || isVariableDeclaration(visited), "Wrong node kind after visit."); return visited; } - export function visitDeclarationName(context: VisitorContext, node: DeclarationName, visitor: Visitor): DeclarationName { + export function visitPropertyName(context: VisitorContext, node: PropertyName, visitor: Visitor): PropertyName { let visited = visit(context, node, visitor); - Debug.assert(!visited || isDeclarationName(visited), "Wrong node kind after visit."); - return visited; + Debug.assert(!visited || isPropertyName(visited), "Wrong node kind after visit."); + return visited; } export function visitBindingElement(context: VisitorContext, node: BindingElement, visitor: Visitor): BindingElement { let visited = visit(context, node, visitor); @@ -857,6 +857,11 @@ namespace ts.transform { Debug.assert(!visited || isExpressionWithTypeArguments(visited), "Wrong node kind after visit."); return visited; } + export function visitDeclarationName(context: VisitorContext, node: DeclarationName, visitor: Visitor): DeclarationName { + let visited = visit(context, node, visitor); + Debug.assert(!visited || isDeclarationName(visited), "Wrong node kind after visit."); + return visited; + } export function visitEnumMember(context: VisitorContext, node: EnumMember, visitor: Visitor): EnumMember { let visited = visit(context, node, visitor); Debug.assert(!visited || isEnumMember(visited), "Wrong node kind after visit."); @@ -917,70 +922,70 @@ namespace ts.transform { Debug.assert(!visited || isJSDocTypeExpression(visited), "Wrong node kind after visit."); return visited; } - export function visitNodeArrayOfTypeParameter(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfTypeParameter(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitTypeParameter); } - export function visitNodeArrayOfParameter(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfParameter(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitParameter); } - export function visitNodeArrayOfDecorator(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfDecorator(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitDecorator); } - export function visitNodeArrayOfModifier(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfModifier(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitModifier); } - export function visitNodeArrayOfVariableDeclaration(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfVariableDeclaration(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitVariableDeclaration); } - export function visitNodeArrayOfBindingElement(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfBindingElement(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitBindingElement); } - export function visitNodeArrayOfTypeNode(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfTypeNode(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitTypeNode); } - export function visitNodeArrayOfTypeElement(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfTypeElement(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitTypeElement); } - export function visitNodeArrayOfTemplateSpan(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfTemplateSpan(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitTemplateSpan); } - export function visitNodeArrayOfExpression(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfExpression(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitExpression); } - export function visitNodeArrayOfObjectLiteralElement(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfObjectLiteralElement(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitObjectLiteralElement); } - export function visitNodeArrayOfJsxChild(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfJsxChild(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitJsxChild); } - export function visitNodeArrayOfJsxAttributeOrJsxSpreadAttribute(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfJsxAttributeOrJsxSpreadAttribute(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitJsxAttributeOrJsxSpreadAttribute); } - export function visitNodeArrayOfCaseOrDefaultClause(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfCaseOrDefaultClause(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitCaseOrDefaultClause); } - export function visitNodeArrayOfHeritageClause(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfHeritageClause(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitHeritageClause); } - export function visitNodeArrayOfClassElement(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfClassElement(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitClassElement); } - export function visitNodeArrayOfExpressionWithTypeArguments(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfExpressionWithTypeArguments(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitExpressionWithTypeArguments); } - export function visitNodeArrayOfEnumMember(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfEnumMember(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitEnumMember); } - export function visitNodeArrayOfImportOrExportSpecifier(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfImportOrExportSpecifier(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitImportOrExportSpecifier); } - export function visitNodeArrayOfJSDocType(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfJSDocType(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitJSDocType); } - export function visitNodeArrayOfJSDocRecordMember(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfJSDocRecordMember(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitJSDocRecordMember); } - export function visitNodeArrayOfJSDocTag(context: VisitorContext, nodes: NodeArray, visitor: Visitor): NodeArray { + export function visitNodeArrayOfJSDocTag(context: VisitorContext, nodes: Array, visitor: Visitor): NodeArray { return >visitNodes(context, nodes, visitor, visitJSDocTag); } } diff --git a/src/compiler/transform.ts b/src/compiler/transform.ts index b889d0413f7..a44ec003b0a 100644 --- a/src/compiler/transform.ts +++ b/src/compiler/transform.ts @@ -10,23 +10,25 @@ namespace ts.transform { } export class VisitorContext { - private generatedNameSet: Map = {}; - private getGeneratedNameForNode: (node: Node) => string; - + private generatedNameSet: Map; + private nodeToGeneratedName: string[]; + private computedPropertyNamesToGeneratedNames: Identifier [] = []; private tempFlagStack: number[] = []; private hoistedVariableDeclarationsStack: VariableDeclaration[][] = []; private hoistedFunctionDeclarationsStack: FunctionDeclaration[][] = []; private statementsStack: Statement[][] = []; private isPinnedOrTripleSlashComment = (comment: CommentRange) => this.isPinnedOrTripleSlashCommentWorker(comment); + public compilerOptions: CompilerOptions; public currentSourceFile: SourceFile; public resolver: EmitResolver; - constructor(currentSourceFile: SourceFile, resolver: EmitResolver, generatedNameSet: Map, getGeneratedNameForNode: (node: Node) => string) { + constructor(compilerOptions: CompilerOptions, currentSourceFile: SourceFile, resolver: EmitResolver, generatedNameSet: Map, nodeToGeneratedName: string[]) { + this.compilerOptions = compilerOptions; this.currentSourceFile = currentSourceFile; this.resolver = resolver; this.generatedNameSet = generatedNameSet; - this.getGeneratedNameForNode = getGeneratedNameForNode; + this.nodeToGeneratedName = nodeToGeneratedName; } public pushLexicalEnvironment(): void { @@ -90,10 +92,23 @@ namespace ts.transform { } } - public getDeclarationName(node: Declaration) { + public getGeneratedNameForNode(node: Node) { + let id = getNodeId(node); + return this.nodeToGeneratedName[id] || (this.nodeToGeneratedName[id] = unescapeIdentifier(this.generateNameForNode(node))); + } + + public nodeHasGeneratedName(node: Node) { + let id = getNodeId(node); + return this.nodeToGeneratedName[id] !== undefined; + } + + public getDeclarationName(node: DeclarationStatement): Identifier; + public getDeclarationName(node: ClassLikeDeclaration): Identifier; + public getDeclarationName(node: Declaration): DeclarationName; + public getDeclarationName(node: Declaration): T | Identifier { let name = node.name; if (name && !nodeIsSynthesized(name)) { - return factory.cloneNode(name); + return factory.cloneNode(name); } else { return factory.createIdentifier( @@ -101,6 +116,18 @@ namespace ts.transform { ); } } + + public getClassMemberPrefix(node: ClassLikeDeclaration, member: ClassElement) { + let expression: Expression = this.getDeclarationName(node); + if (!(member.flags & NodeFlags.Static)) { + expression = factory.createPropertyAccessExpression2( + expression, + factory.createIdentifier("prototype") + ); + } + + return expression; + } public createUniqueIdentifier(baseName: string): Identifier { let name = this.makeUniqueName(baseName); @@ -255,6 +282,61 @@ namespace ts.transform { && !hasProperty(this.currentSourceFile.identifiers, name) && !hasProperty(this.generatedNameSet, name); } + + private isUniqueLocalName(name: string, container: Node): boolean { + container = getOriginalNode(container); + for (let node = container; isNodeDescendentOf(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; + } + + private generateNameForNode(node: Node) { + switch (node.kind) { + case SyntaxKind.Identifier: + return this.makeUniqueName((node).text); + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.EnumDeclaration: + return this.generateNameForModuleOrEnum(node); + case SyntaxKind.ImportDeclaration: + case SyntaxKind.ExportDeclaration: + return this.generateNameForImportOrExportDeclaration(node); + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ExportAssignment: + return this.generateNameForExportDefault(); + case SyntaxKind.ClassExpression: + return this.generateNameForClassExpression(); + case SyntaxKind.ComputedPropertyName: + return this.makeTempVariableName(TempFlags.Auto); + } + } + + private generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) { + let name = node.name.text; + // Use module/enum name itself if it is unique, otherwise make a unique variation + return this.isUniqueLocalName(name, node) ? name : this.makeUniqueName(name); + } + + private generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) { + let expr = getExternalModuleName(node); + let baseName = expr.kind === SyntaxKind.StringLiteral ? + escapeIdentifier(makeIdentifierFromModuleName((expr).text)) : "module"; + return this.makeUniqueName(baseName); + } + + private generateNameForExportDefault() { + return this.makeUniqueName("default"); + } + + private generateNameForClassExpression() { + return this.makeUniqueName("class"); + } } export type Visitor = (context: VisitorContext, node: Node) => Node; diff --git a/src/compiler/transforms/es6.ts b/src/compiler/transforms/es6.ts index 63778bf7660..35e5f108657 100644 --- a/src/compiler/transforms/es6.ts +++ b/src/compiler/transforms/es6.ts @@ -80,7 +80,13 @@ namespace ts.transform { case SyntaxKind.MethodDeclaration: // TypeScript method declarations may be 'async', and may have decorators. return transformMethodDeclaration(context, node); - + + case SyntaxKind.GetAccessor: + return transformGetAccessor(context, node); + + case SyntaxKind.SetAccessor: + return transformSetAccessor(context, node); + default: return transform.accept(context, node, transformNode); } @@ -88,10 +94,6 @@ namespace ts.transform { function transformClassDeclaration(context: VisitorContext, node: ClassDeclaration): ClassDeclaration { // TODO(rbuckton): Handle decorators, for now we don't change the class and let the old emitter handle this - if (node.decorators) { - return node; - } - let baseTypeNode = getClassExtendsHeritageClauseElement(node); let modifiers = visitNodeArrayOfModifier(context, node.modifiers, transformNodeWorker); let heritageClauses = visitNodeArrayOfHeritageClause(context, node.heritageClauses, transformNodeWorker); @@ -100,25 +102,41 @@ namespace ts.transform { if (ctor) { members = factory.createNodeArray([ctor, ...members]); } - - let newNode = factory.updateClassDeclaration( - node, - /*decorators*/ undefined, - /*modifiers*/ modifiers, - node.name, - /*typeParameters*/ undefined, - /*heritageClauses*/ heritageClauses, - /*members*/ members - ); + + if (node.decorators) { + let newNode = factory.createVariableStatement2( + context.getDeclarationName(node), + factory.createClassExpression2( + node.name ? context.createUniqueIdentifier(node.name.text) : undefined, + heritageClauses ? heritageClauses[0] : undefined, + members + ), + /*location*/ node, + NodeFlags.Let + ); + newNode.original = node; + context.emitStatement(newNode); + } + else { + let newNode = factory.updateClassDeclaration( + node, + /*decorators*/ undefined, + /*modifiers*/ modifiers, + node.name, + /*typeParameters*/ undefined, + /*heritageClauses*/ heritageClauses, + /*members*/ members + ); + } let staticPropertyAssignments = getInitializedProperties(node, /*isStatic*/ true); if (staticPropertyAssignments) { - context.emitStatement(newNode); emitPropertyDeclarations(context, node, staticPropertyAssignments); - return undefined; } - - return newNode; + + // Transform any decorators into following statements + emitDecoratorsOfClass(context, node); + return undefined; } function transformClassExpression(context: VisitorContext, node: ClassExpression): LeftHandSideExpression { @@ -383,6 +401,376 @@ namespace ts.transform { return missing; } - return node; + let modifiers = visitNodeArrayOfModifier(context, node.modifiers, transformNode); + let name = transformPropertyName(context, node); + let parameters = visitNodeArrayOfParameter(context, node.parameters, transformNode); + let body = visitBlock(context, node.body, transformNode); + return factory.updateMethodDeclaration( + node, + /*decorators*/ undefined, + modifiers, + name, + /*typeParameters*/ undefined, + parameters, + /*typeNode*/ undefined, + body + ); + } + + function transformGetAccessor(context: VisitorContext, node: GetAccessorDeclaration) { + let modifiers = visitNodeArrayOfModifier(context, node.modifiers, transformNode); + let name = transformPropertyName(context, node); + let parameters = visitNodeArrayOfParameter(context, node.parameters, transformNode); + let body = visitBlock(context, node.body, transformNode); + return factory.updateGetAccessor( + node, + /*decorators*/ undefined, + modifiers, + name, + parameters, + /*typeNode*/ undefined, + body + ); + } + + function transformSetAccessor(context: VisitorContext, node: SetAccessorDeclaration) { + let modifiers = visitNodeArrayOfModifier(context, node.modifiers, transformNode); + let name = transformPropertyName(context, node); + let parameters = visitNodeArrayOfParameter(context, node.parameters, transformNode); + let body = visitBlock(context, node.body, transformNode); + return factory.updateSetAccessor( + node, + /*decorators*/ undefined, + modifiers, + name, + parameters, + /*typeNode*/ undefined, + body + ); + } + + function getExpressionForPropertyName(context: VisitorContext, container: Declaration): Expression { + let name = transformPropertyName(context, container); + if (isComputedPropertyName(name)) { + return name.expression; + } + else if (isStringLiteral(name)) { + return factory.createStringLiteral(name.text); + } + } + + function transformPropertyName(context: VisitorContext, container: Declaration): PropertyName { + let name = context.getDeclarationName(container); + if (isComputedPropertyName(name)) { + if (context.nodeHasGeneratedName(name)) { + return factory.createIdentifier(context.getGeneratedNameForNode(name)); + } + + let expression = visitExpression(context, name.expression, transformNode); + if (nodeCanBeDecorated(container) && nodeIsDecorated(container)) { + let generatedName = factory.createIdentifier(context.getGeneratedNameForNode(name)); + context.hoistVariableDeclaration(generatedName); + expression = factory.createAssignmentExpression( + generatedName, + expression + ); + } + + return factory.updateComputedPropertyName( + name, + expression + ); + } + else if (isPropertyName(name)) { + return name; + } + + Debug.fail("Binding patterns cannot be used as property names."); + } + + function emitDecoratorsOfClass(context: VisitorContext, node: ClassLikeDeclaration) { + emitDecoratorsOfMembers(context, node, /*isStatic*/ false); + emitDecoratorsOfMembers(context, node, /*isStatic*/ true); + emitDecoratorsOfConstructor(context, node); + } + + function emitDecoratorsOfMembers(context: VisitorContext, node: ClassLikeDeclaration, isStatic: boolean) { + for (let member of node.members) { + // only emit members in the correct group + if (isStatic !== ((member.flags & NodeFlags.Static) !== 0)) { + continue; + } + + // skip members that cannot be decorated (such as the constructor) + // skip a member if it or any of its parameters are not decorated + if (!nodeCanBeDecorated(member) || !nodeOrChildIsDecorated(member)) { + continue; + } + + emitDecoratorsOfMember(context, node, member); + } + } + + function emitDecoratorsOfConstructor(context: VisitorContext, node: ClassLikeDeclaration) { + let decorators = node.decorators; + let constructor = getFirstConstructorWithBody(node); + let hasDecoratedParameters = constructor && forEach(constructor.parameters, nodeIsDecorated); + + // skip decoration of the constructor if neither it nor its parameters are decorated + if (!decorators && !hasDecoratedParameters) { + return; + } + + // Emit the call to __decorate. Given the class: + // + // @dec + // class C { + // } + // + // The emit for the class is: + // + // C = __decorate([dec], C); + // + + let decoratorExpressions: Expression[] = []; + if (decorators) { + for (let decorator of decorators) { + decoratorExpressions.push(visitExpression(context, decorator.expression, transformNode)) + } + } + + if (constructor) { + emitDecoratorsOfParameters(context, constructor.parameters, decoratorExpressions); + } + + if (context.compilerOptions.emitDecoratorMetadata) { + emitSerializedTypeMetadata(context, node, decoratorExpressions); + } + + context.emitAssignmentStatement( + context.getDeclarationName(node), + factory.createCallExpression2( + factory.createIdentifier("__decorate"), + [ + factory.createArrayLiteralExpression(decoratorExpressions), + context.getDeclarationName(node) + ] + ) + ); + } + + function emitDecoratorsOfMember(context: VisitorContext, node: ClassLikeDeclaration, member: ClassElement) { + let decorators: Decorator[]; + let parameters: ParameterDeclaration[]; + + // skip an accessor declaration if it is not the first accessor + if (isAccessor(member) && member.body) { + let accessors = getAllAccessorDeclarations(node.members, member); + if (member !== accessors.firstAccessor) { + return; + } + + // get the decorators from the first accessor with decorators + decorators = accessors.firstAccessor.decorators; + if (!decorators && accessors.secondAccessor) { + decorators = accessors.secondAccessor.decorators; + } + + // we only decorate parameters of the set accessor + parameters = accessors.setAccessor + ? accessors.setAccessor.parameters + : undefined; + } + else { + decorators = member.decorators; + + // we only decorate the parameters here if this is a method + if (isMethodDeclaration(member) && member.body) { + parameters = member.parameters; + } + } + + // Emit the call to __decorate. Given the following: + // + // class C { + // @dec method(@dec2 x) {} + // @dec get accessor() {} + // @dec prop; + // } + // + // The emit for a method is: + // + // Object.defineProperty(C.prototype, "method", + // __decorate([ + // dec, + // __param(0, dec2), + // __metadata("design:type", Function), + // __metadata("design:paramtypes", [Object]), + // __metadata("design:returntype", void 0) + // ], C.prototype, "method", Object.getOwnPropertyDescriptor(C.prototype, "method"))); + // + // The emit for an accessor is: + // + // Object.defineProperty(C.prototype, "accessor", + // __decorate([ + // dec + // ], C.prototype, "accessor", Object.getOwnPropertyDescriptor(C.prototype, "accessor"))); + // + // The emit for a property is: + // + // __decorate([ + // dec + // ], C.prototype, "prop"); + // + + let decoratorExpressions: Expression[] = []; + if (decorators) { + for (let decorator of decorators) { + decoratorExpressions.push(visitExpression(context, decorator.expression, transformNode)) + } + } + + if (parameters) { + emitDecoratorsOfParameters(context, parameters, decoratorExpressions); + } + + if (context.compilerOptions.emitDecoratorMetadata) { + emitSerializedTypeMetadata(context, node, decoratorExpressions); + } + + let prefix = context.getClassMemberPrefix(node, member); + let decorateCallArguments: Expression[] = [ + factory.createArrayLiteralExpression(decoratorExpressions), + prefix, + getExpressionForPropertyName(context, member) + ]; + + let expression: Expression = factory.createCallExpression2( + factory.createIdentifier("__decorate"), + decorateCallArguments + ); + + if (!isPropertyDeclaration(member)) { + decorateCallArguments.push( + factory.createCallExpression2( + factory.createPropertyAccessExpression2( + factory.createIdentifier("Object"), + factory.createIdentifier("getOwnPropertyDescriptor") + ), + [ + prefix, + getExpressionForPropertyName(context, member) + ] + ) + ); + + expression = factory.createCallExpression2( + factory.createPropertyAccessExpression2( + factory.createIdentifier("Object"), + factory.createIdentifier("defineProperty") + ), + [ + prefix, + getExpressionForPropertyName(context, member), + expression + ] + ); + } + + context.emitExpressionStatement(expression); + } + + function emitDecoratorsOfParameters(context: VisitorContext, parameters: ParameterDeclaration[], expressions: Expression[]) { + for (let parameterIndex = 0; parameterIndex < parameters.length; parameterIndex++) { + let parameter = parameters[parameterIndex]; + if (nodeIsDecorated(parameter)) { + for (let decorator of parameter.decorators) { + expressions.push( + factory.createCallExpression2( + factory.createIdentifier("__param"), + [ + factory.createNumericLiteral2(parameterIndex), + visitExpression(context, decorator.expression, transformNode) + ] + ) + ); + } + } + } + } + + function emitSerializedTypeMetadata(context: VisitorContext, node: Declaration, expressions: Expression[]) { + if (shouldEmitTypeMetadata(node)) { + expressions.push( + factory.createCallExpression2( + factory.createIdentifier("__metadata"), + [ + factory.createStringLiteral("design:type"), + // TODO + ] + ) + ); + } + if (shouldEmitParamTypesMetadata(node)) { + expressions.push( + factory.createCallExpression2( + factory.createIdentifier("__metadata"), + [ + factory.createStringLiteral("design:paramtypes"), + // TODO + ] + ) + ); + } + if (shouldEmitReturnTypeMetadata(node)) { + expressions.push( + factory.createCallExpression2( + factory.createIdentifier("__metadata"), + [ + factory.createStringLiteral("design:returntype"), + // TODO + ] + ) + ); + } + } + + function shouldEmitTypeMetadata(node: Declaration): boolean { + // This method determines whether to emit the "design:type" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. + switch (node.kind) { + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.PropertyDeclaration: + return true; + } + + return false; + } + + function shouldEmitReturnTypeMetadata(node: Declaration): boolean { + // This method determines whether to emit the "design:returntype" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. + switch (node.kind) { + case SyntaxKind.MethodDeclaration: + return true; + } + return false; + } + + function shouldEmitParamTypesMetadata(node: Declaration): boolean { + // This method determines whether to emit the "design:paramtypes" metadata based on the node's kind. + // The caller should have already tested whether the node has decorators and whether the emitDecoratorMetadata + // compiler option is set. + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.SetAccessor: + return true; + } + return false; } } \ No newline at end of file diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6e2586399b8..6c818a7b34e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -730,6 +730,8 @@ namespace ts { export type DeclarationName = Identifier | LiteralExpression | ComputedPropertyName | BindingPattern; + export type PropertyName = Identifier | LiteralExpression | ComputedPropertyName; + // @factoryhidden("decorators", false) // @factoryhidden("modifiers", false) export interface Declaration extends Node { @@ -817,30 +819,34 @@ namespace ts { } // @kind(SyntaxKind.PropertySignature) + // @factoryorder("decorators", "modifiers", "name", "questionToken", "type") export interface PropertySignature extends TypeElement { - name: DeclarationName; // Declared property name + name: PropertyName; // @factoryparam questionToken?: Node; // Present on optional property type?: TypeNode; // Optional type annotation } // @kind(SyntaxKind.PropertyDeclaration) - // @factoryorder("decorators", "modifiers", "name", "questionToken", "type", "initializer") - export interface PropertyDeclaration extends PropertySignature, ClassElement { - name: DeclarationName; // Declared property name + // @factoryorder("decorators", "modifiers", "name", "type", "initializer") + export interface PropertyDeclaration extends ClassElement { + // @factoryhidden + questionToken?: Node; // Present for use with reporting a grammar error + name: PropertyName; + type?: TypeNode; initializer?: Expression; // Optional initializer } export interface ObjectLiteralElement extends Declaration { _objectLiteralBrandBrand: any; - } + } // @kind(SyntaxKind.PropertyAssignment) // @factoryhidden("decorators", true) // @factoryhidden("modifiers", true) export interface PropertyAssignment extends ObjectLiteralElement { _propertyAssignmentBrand: any; - name: DeclarationName; + name: PropertyName; // @factoryparam questionToken?: Node; initializer: Expression; @@ -918,6 +924,7 @@ namespace ts { // @factoryhidden("body", true) // @factoryorder("decorators", "modifiers", "asteriskToken", "name", "questionToken", "typeParameters", "parameters", "type") export interface MethodSignature extends SignatureDeclaration, TypeElement { + name: PropertyName; } // Note that a MethodDeclaration is considered both a ClassElement and an ObjectLiteralElement. @@ -934,6 +941,7 @@ namespace ts { // @factoryhidden("body", false) // @factoryorder("decorators", "modifiers", "asteriskToken", "name", "typeParameters", "parameters", "type", "body") export interface MethodDeclaration extends FunctionLikeDeclaration, ClassElement, ObjectLiteralElement { + name: PropertyName; body?: Block; } @@ -962,7 +970,7 @@ namespace ts { // SyntaxKind.SetAccessor export interface AccessorDeclaration extends FunctionLikeDeclaration, ClassElement, ObjectLiteralElement { _accessorDeclarationBrand: any; - + name: PropertyName; // @visitor("visitBlockInNewLexicalScope") body: Block; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 417f1023a9e..a6f9450a29c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -594,7 +594,7 @@ namespace ts { return false; } - export function isAccessor(node: Node): boolean { + export function isAccessor(node: Node): node is AccessorDeclaration { return node && (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor); } @@ -758,6 +758,15 @@ namespace ts { } } + export function isNodeDescendentOf(node: Node, ancestor: Node): boolean { + while (node) { + if (node === ancestor) return true; + node = node.parent; + } + return false; + } + + export function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression { if (node) { switch (node.kind) {