From a66b0ae54ca22cce3eb08da0410aebbe4da3dd5c Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Wed, 26 Oct 2016 16:57:43 -0700 Subject: [PATCH] Split CodeFixes in Separate Files --- Jakefile.js | 11 +- ...sDoesntImplementInheritedAbstractMember.ts | 34 +++ .../fixClassIncorrectlyImplementsInterface.ts | 39 +++ ... => fixClassSuperMustPrecedeThisAccess.ts} | 23 -- .../fixConstructorForDerivedNeedSuperCall.ts | 20 ++ ...> fixExtendsInterfaceBecomesImplements.ts} | 0 src/services/codefixes/fixes.ts | 8 +- src/services/codefixes/interfaceFixes.ts | 228 ------------------ src/services/tsconfig.json | 7 +- src/services/utilities.ts | 161 +++++++++++++ 10 files changed, 275 insertions(+), 256 deletions(-) create mode 100644 src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts create mode 100644 src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts rename src/services/codefixes/{superFixes.ts => fixClassSuperMustPrecedeThisAccess.ts} (68%) create mode 100644 src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts rename src/services/codefixes/{changeExtendsToImplementsFix.ts => fixExtendsInterfaceBecomesImplements.ts} (100%) delete mode 100644 src/services/codefixes/interfaceFixes.ts diff --git a/Jakefile.js b/Jakefile.js index cda7e2ca882..fcb5a482acd 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -149,6 +149,7 @@ var servicesSources = [ "signatureHelp.ts", "symbolDisplay.ts", "transpile.ts", + // Formatting "formatting/formatting.ts", "formatting/formattingContext.ts", "formatting/formattingRequestKind.ts", @@ -164,7 +165,15 @@ var servicesSources = [ "formatting/rulesMap.ts", "formatting/rulesProvider.ts", "formatting/smartIndenter.ts", - "formatting/tokenRange.ts" + "formatting/tokenRange.ts", + // CodeFixes + "codeFixes/codeFixProvider.ts", + "codeFixes/fixes.ts", + "codeFixes/fixExtendsInterfaceBecomesImplements.ts", + "codeFixes/fixClassIncorrectlyImplementsInterface.ts", + "codeFixes/fixClassDoesntImplementInheritedAbstractMember.ts", + "codeFixes/fixClassSuperMustPrecedeThisAccess.ts", + "codeFixes/fixConstructorForDerivedNeedSuperCall.ts" ].map(function (f) { return path.join(servicesDirectory, f); })); diff --git a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts new file mode 100644 index 00000000000..ce7eb04d2cd --- /dev/null +++ b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts @@ -0,0 +1,34 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2.code], + getCodeActions: (context: CodeFixContext) => { + const sourceFile = context.sourceFile; + const start = context.span.start; + const token = getTokenAtPosition(sourceFile, start); + const checker = context.program.getTypeChecker(); + + if (token.kind === SyntaxKind.Identifier && isClassLike(token.parent)) { + const classDeclaration = token.parent; + const startPos = classDeclaration.members.pos; + // TODO: (arozga) actually get abstract members + const abstractClassMembers = ts.map(getNamedAbstractClassMembers(classDeclaration), member => member.name.getText()); + const trackingAddedMembers: string[] = []; + const extendsClause = ts.getClassExtendsHeritageClauseElement(classDeclaration); + let textChanges = getCodeFixChanges(extendsClause, abstractClassMembers, startPos, checker, /*reference*/ false, trackingAddedMembers, context.newLineCharacter); + + if (textChanges.length > 0) { + return [{ + description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class), + changes: [{ + fileName: sourceFile.fileName, + textChanges: textChanges + }] + }]; + } + } + + return undefined; + } + }); +} \ No newline at end of file diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts new file mode 100644 index 00000000000..9ff3a554c23 --- /dev/null +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -0,0 +1,39 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Class_0_incorrectly_implements_interface_1.code], + getCodeActions: (context: CodeFixContext) => { + const sourceFile = context.sourceFile; + const start = context.span.start; + const token = getTokenAtPosition(sourceFile, start); + const checker = context.program.getTypeChecker(); + + if (token.kind === SyntaxKind.Identifier && isClassLike(token.parent)) { + const classDeclaration = token.parent; + const startPos: number = classDeclaration.members.pos; + const classMembers = ts.map(getNamedClassMembers(classDeclaration), member => member.name.getText()); + const trackingAddedMembers: string[] = []; + const interfaceClauses = ts.getClassImplementsHeritageClauseElements(classDeclaration); + + let textChanges: TextChange[] = undefined; + + for (let i = 0; interfaceClauses && i < interfaceClauses.length; i++) { + let newChanges = getCodeFixChanges(interfaceClauses[i], classMembers, startPos, checker, /*reference*/ false, trackingAddedMembers, context.newLineCharacter); + textChanges = textChanges ? textChanges.concat(newChanges) : newChanges; + } + + if (textChanges && textChanges.length > 0) { + return [{ + description: getLocaleSpecificMessage(Diagnostics.Implement_interface_on_class), + changes: [{ + fileName: sourceFile.fileName, + textChanges: textChanges + }] + }]; + } + } + + return undefined; + } + }); +} \ No newline at end of file diff --git a/src/services/codefixes/superFixes.ts b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts similarity index 68% rename from src/services/codefixes/superFixes.ts rename to src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts index f117799f3e1..4528c48774d 100644 --- a/src/services/codefixes/superFixes.ts +++ b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts @@ -1,28 +1,5 @@ /* @internal */ namespace ts.codefix { - function getOpenBraceEnd(constructor: ConstructorDeclaration, sourceFile: SourceFile) { - // First token is the open curly, this is where we want to put the 'super' call. - return constructor.body.getFirstToken(sourceFile).getEnd(); - } - - registerCodeFix({ - errorCodes: [Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call.code], - getCodeActions: (context: CodeFixContext) => { - const sourceFile = context.sourceFile; - const token = getTokenAtPosition(sourceFile, context.span.start); - - if (token.kind !== SyntaxKind.ConstructorKeyword) { - return undefined; - } - - const newPosition = getOpenBraceEnd(token.parent, sourceFile); - return [{ - description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call), - changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "super();", span: { start: newPosition, length: 0 } }] }] - }]; - } - }); - registerCodeFix({ errorCodes: [Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class.code], getCodeActions: (context: CodeFixContext) => { diff --git a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts new file mode 100644 index 00000000000..0dede87cf28 --- /dev/null +++ b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts @@ -0,0 +1,20 @@ +/* @internal */ +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call.code], + getCodeActions: (context: CodeFixContext) => { + const sourceFile = context.sourceFile; + const token = getTokenAtPosition(sourceFile, context.span.start); + + if (token.kind !== SyntaxKind.ConstructorKeyword) { + return undefined; + } + + const newPosition = getOpenBraceEnd(token.parent, sourceFile); + return [{ + description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call), + changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "super();", span: { start: newPosition, length: 0 } }] }] + }]; + } + }); +} \ No newline at end of file diff --git a/src/services/codefixes/changeExtendsToImplementsFix.ts b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts similarity index 100% rename from src/services/codefixes/changeExtendsToImplementsFix.ts rename to src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index b1fdb9d43da..7df58b03f81 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -1,3 +1,5 @@ -/// -/// -/// +/// +/// +/// +/// +/// \ No newline at end of file diff --git a/src/services/codefixes/interfaceFixes.ts b/src/services/codefixes/interfaceFixes.ts deleted file mode 100644 index c379884ab5b..00000000000 --- a/src/services/codefixes/interfaceFixes.ts +++ /dev/null @@ -1,228 +0,0 @@ -/* @internal */ -namespace ts.codefix { - registerCodeFix({ - errorCodes: [Diagnostics.Class_0_incorrectly_implements_interface_1.code], - getCodeActions: (context: CodeFixContext) => { - const sourceFile = context.sourceFile; - const start = context.span.start; - const token = getTokenAtPosition(sourceFile, start); - const checker = context.program.getTypeChecker(); - - if (token.kind === SyntaxKind.Identifier && isClassLike(token.parent)) { - const classDeclaration = token.parent; - const startPos: number = classDeclaration.members.pos; - const classMembers = ts.map(getNamedClassMemberDeclarations(classDeclaration), member => member.name.getText()); - const trackingAddedMembers: string[] = []; - const interfaceClauses = ts.getClassImplementsHeritageClauseElements(classDeclaration); - - let textChanges: TextChange[] = undefined; - - for (let i = 0; interfaceClauses && i < interfaceClauses.length; i++) { - let newChanges = getChanges(interfaceClauses[i], classMembers, startPos, checker, /*reference*/ false, trackingAddedMembers, context.newLineCharacter); - textChanges = textChanges ? textChanges.concat(newChanges) : newChanges; - } - - if (textChanges && textChanges.length > 0) { - return [{ - description: getLocaleSpecificMessage(Diagnostics.Implement_interface_on_class), - changes: [{ - fileName: sourceFile.fileName, - textChanges: textChanges - }] - }]; - } - } - - return undefined; - } - }); - - registerCodeFix({ - errorCodes: [Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2.code], - getCodeActions: (context: CodeFixContext) => { - const sourceFile = context.sourceFile; - const start = context.span.start; - const token = getTokenAtPosition(sourceFile, start); - const checker = context.program.getTypeChecker(); - - let textChanges: TextChange[] = []; - - if (token.kind === SyntaxKind.Identifier && isClassLike(token.parent)) { - const classDeclaration = token.parent; - const startPos = classDeclaration.members.pos; - const abstractClassMembers = ts.map(getNamedClassAbstractMemberDeclarations(classDeclaration), member => member.name.getText()); - const trackingAddedMembers: string[] = []; - const extendsClause = ts.getClassExtendsHeritageClauseElement(classDeclaration); - textChanges = textChanges.concat(getChanges(extendsClause, abstractClassMembers, startPos, checker, /*reference*/ false, trackingAddedMembers, context.newLineCharacter)); - } - - if (textChanges.length > 0) { - return [{ - description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class), - changes: [{ - fileName: sourceFile.fileName, - textChanges: textChanges - }] - }]; - } - - return undefined; - } - }); - - function getChanges(interfaceClause: Node, existingMembers: string[], startPos: number, checker: TypeChecker, reference: boolean, trackingAddedMembers: string[], newLineCharacter: string): TextChange[] { - const type = checker.getTypeAtLocation(interfaceClause); - const changesArray: TextChange[] = []; - - if (type && type.symbol && type.symbol.declarations) { - const interfaceMembers = getMembers(type.symbol.declarations[0], checker); - for(let interfaceMember of interfaceMembers){ - if (interfaceMember.name && existingMembers.indexOf(interfaceMember.name.getText()) === -1) { - if (interfaceMember.kind === SyntaxKind.PropertySignature) { - const interfaceProperty = interfaceMember; - if (trackingAddedMembers.indexOf(interfaceProperty.name.getText()) === -1) { - let propertyText = ""; - if (reference) { - propertyText = `${interfaceProperty.name.getText()} : ${getDefaultValue(interfaceProperty.type.kind)},${newLineCharacter}`; - } - else { - propertyText = interfaceProperty.getText(); - const stringToAdd = !(propertyText.match(/;$/)) ? `;${newLineCharacter}` : newLineCharacter; - propertyText += stringToAdd; - } - changesArray.push({ newText: propertyText, span: { start: startPos, length: 0 } }); - trackingAddedMembers.push(interfaceProperty.name.getText()); - } - } - else if (interfaceMember.kind === SyntaxKind.MethodSignature || interfaceMember.kind === SyntaxKind.MethodDeclaration) { - const interfaceMethod = interfaceMember; - handleMethods(interfaceMethod, startPos, reference, trackingAddedMembers, changesArray, newLineCharacter); - } - } - } - } - - if (reference && existingMembers.length === 0 && changesArray.length > 0) { - let lastValue = changesArray[changesArray.length - 1].newText; - lastValue = `${lastValue.substr(0, lastValue.length - (newLineCharacter.length + 1))} ${newLineCharacter}`; - changesArray[changesArray.length - 1].newText = lastValue; - } - - return changesArray; - } - - function getMembers(declaration: InterfaceDeclaration, checker: TypeChecker): TypeElement[] { - const clauses = getInterfaceBaseTypeNodes(declaration); - let result: TypeElement[] = []; - for (let i = 0; clauses && i < clauses.length; i++) { - const type = checker.getTypeAtLocation(clauses[i]); - if (type && type.symbol && type.symbol.declarations) { - result = result.concat(getMembers(type.symbol.declarations[0], checker)); - } - } - - if (declaration.members) { - result = result.concat(declaration.members); - } - - return result; - } - - function getNamedClassMemberDeclarations(classDeclaration: ClassDeclaration): ClassElement[] { - return classDeclaration.members.filter(member => member.name); - } - - function getNamedClassAbstractMemberDeclarations(classDeclaration: ClassDeclaration): ClassElement[] { - return getNamedClassMemberDeclarations(classDeclaration).filter(member => getModifierFlags(member) & ModifierFlags.Abstract); - } - - /* - function getMembersAndStartPosFromReference(variableDeclaration: VariableDeclaration): { startPos: number, members: string[] } { - const children = variableDeclaration.getChildren(); - const variableMembers: string[] = []; - let startPos = 0; - - ts.forEach(children, child => { - if (child.kind === SyntaxKind.ObjectLiteralExpression) { - const properties = (child).properties; - if (properties) { - startPos = properties.pos; - } - for (let j = 0; properties && j < properties.length; j++) { - if (properties[j].name) { - variableMembers.push(properties[j].name.getText()); - } - } - } - }); - - return { startPos: startPos, members: variableMembers }; - } - */ - - function getDefaultValue(kind: SyntaxKind): string { - switch (kind) { - case SyntaxKind.StringKeyword: - return '""'; - case SyntaxKind.BooleanKeyword: - return "false"; - case SyntaxKind.NumberKeyword: - return "0"; - default: - return "null"; - } - } - - function handleMethods(interfaceMethod: MethodSignature, startPos: number, isReference: boolean, trackingAddedMembers: string[], textChanges: TextChange[], newLineCharacter: string) { - const methodBody = "throw new Error('Method not Implemented');"; - - if (trackingAddedMembers.indexOf(interfaceMethod.name.getText())) { - const methodName = interfaceMethod.name.getText(); - const typeParameterArray: string[] = []; - - for (let i = 0; interfaceMethod.typeParameters && i < interfaceMethod.typeParameters.length; i++) { - typeParameterArray.push(interfaceMethod.typeParameters[i].getText()); - } - - const parameterArray: string[] = []; - for (let j = 0; interfaceMethod.parameters && j < interfaceMethod.parameters.length; j++) { - parameterArray.push(interfaceMethod.parameters[j].getText()); - } - - let methodText = methodName; - if (typeParameterArray.length > 0) { - methodText += "<"; - } - - for (let k = 0; k < typeParameterArray.length; k++) { - methodText += typeParameterArray[k]; - if (k !== typeParameterArray.length - 1) { - methodText += ","; - } - } - - if (typeParameterArray.length > 0) { - methodText += ">"; - } - - methodText += "("; - for (let k = 0; k < parameterArray.length; k++) { - methodText += parameterArray[k]; - if (k !== parameterArray.length - 1) { - methodText += ","; - } - } - - methodText += `)`; - if (interfaceMethod.type) { - methodText += ":" + interfaceMethod.type.getText(); - } - - methodText += `{${newLineCharacter}${methodBody}${newLineCharacter}`; - methodText = isReference ? methodText.concat(`},${newLineCharacter}`) : methodText.concat(`}${newLineCharacter}`); - - textChanges.push({ newText: methodText, span: { start: startPos, length: 0 } }); - trackingAddedMembers.push(interfaceMethod.name.getText()); - } - } -} diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index e81db68325c..b890e27f01e 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -85,6 +85,11 @@ "formatting/smartIndenter.ts", "formatting/tokenRange.ts", "codeFixes/codeFixProvider.ts", - "codeFixes/fixes.ts" + "codeFixes/fixes.ts", + "codeFixes/fixExtendsInterfaceBecomesImplements.ts", + "codeFixes/fixClassIncorrectlyImplementsInterface.ts", + "codeFixes/fixClassDoesntImplementInheritedAbstractMember.ts", + "codeFixes/fixClassSuperMustPrecedeThisAccess.ts", + "codeFixes/fixConstructorForDerivedNeedSuperCall.ts" ] } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 8fd5f510be0..ee8f348d15d 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1358,4 +1358,165 @@ namespace ts { diagnostics: error ? concatenate(diagnostics, [error]) : diagnostics }; } + + export function getCodeFixChanges(interfaceClause: Node, existingMembers: string[], startPos: number, checker: TypeChecker, reference: boolean, trackingAddedMembers: string[], newLineCharacter: string): TextChange[] { + const type = checker.getTypeAtLocation(interfaceClause); + const changesArray: TextChange[] = []; + + if (type && type.symbol && type.symbol.declarations) { + const interfaceMembers = getInterfaceMembers(type.symbol.declarations[0], checker); + for(let interfaceMember of interfaceMembers){ + if (interfaceMember.name && existingMembers.indexOf(interfaceMember.name.getText()) === -1) { + if (interfaceMember.kind === SyntaxKind.PropertySignature) { + const interfaceProperty = interfaceMember; + if (trackingAddedMembers.indexOf(interfaceProperty.name.getText()) === -1) { + let propertyText = ""; + if (reference) { + propertyText = `${interfaceProperty.name.getText()} : ${getDefaultValue(interfaceProperty.type.kind)},${newLineCharacter}`; + } + else { + propertyText = interfaceProperty.getText(); + const stringToAdd = !(propertyText.match(/;$/)) ? `;${newLineCharacter}` : newLineCharacter; + propertyText += stringToAdd; + } + changesArray.push({ newText: propertyText, span: { start: startPos, length: 0 } }); + trackingAddedMembers.push(interfaceProperty.name.getText()); + } + } + else if (interfaceMember.kind === SyntaxKind.MethodSignature || interfaceMember.kind === SyntaxKind.MethodDeclaration) { + const interfaceMethod = interfaceMember; + handleMethods(interfaceMethod, startPos, reference, trackingAddedMembers, changesArray, newLineCharacter); + } + } + } + } + + if (reference && existingMembers.length === 0 && changesArray.length > 0) { + let lastValue = changesArray[changesArray.length - 1].newText; + lastValue = `${lastValue.substr(0, lastValue.length - (newLineCharacter.length + 1))} ${newLineCharacter}`; + changesArray[changesArray.length - 1].newText = lastValue; + } + + return changesArray; + } + + function getInterfaceMembers(declaration: InterfaceDeclaration, checker: TypeChecker): TypeElement[] { + const clauses = getInterfaceBaseTypeNodes(declaration); + let result: TypeElement[] = []; + for (let i = 0; clauses && i < clauses.length; i++) { + const type = checker.getTypeAtLocation(clauses[i]); + if (type && type.symbol && type.symbol.declarations) { + result = result.concat(getInterfaceMembers(type.symbol.declarations[0], checker)); + } + } + + if (declaration.members) { + result = result.concat(declaration.members); + } + + return result; + } + + export function getNamedClassMembers(classDeclaration: ClassDeclaration): ClassElement[] { + return classDeclaration.members.filter(member => member.name); + } + + export function getNamedAbstractClassMembers(classDeclaration: ClassDeclaration): ClassElement[] { + return getNamedClassMembers(classDeclaration).filter(member => getModifierFlags(member) & ModifierFlags.Abstract); + } + + /* + function getMembersAndStartPosFromReference(variableDeclaration: VariableDeclaration): { startPos: number, members: string[] } { + const children = variableDeclaration.getChildren(); + const variableMembers: string[] = []; + let startPos = 0; + + ts.forEach(children, child => { + if (child.kind === SyntaxKind.ObjectLiteralExpression) { + const properties = (child).properties; + if (properties) { + startPos = properties.pos; + } + for (let j = 0; properties && j < properties.length; j++) { + if (properties[j].name) { + variableMembers.push(properties[j].name.getText()); + } + } + } + }); + + return { startPos: startPos, members: variableMembers }; + } + */ + + function getDefaultValue(kind: SyntaxKind): string { + switch (kind) { + case SyntaxKind.StringKeyword: + return '""'; + case SyntaxKind.BooleanKeyword: + return "false"; + case SyntaxKind.NumberKeyword: + return "0"; + default: + return "null"; + } + } + + function handleMethods(interfaceMethod: MethodSignature, startPos: number, isReference: boolean, trackingAddedMembers: string[], textChanges: TextChange[], newLineCharacter: string) { + const methodBody = "throw new Error('Method not Implemented');"; + + if (trackingAddedMembers.indexOf(interfaceMethod.name.getText())) { + const methodName = interfaceMethod.name.getText(); + const typeParameterArray: string[] = []; + + for (let i = 0; interfaceMethod.typeParameters && i < interfaceMethod.typeParameters.length; i++) { + typeParameterArray.push(interfaceMethod.typeParameters[i].getText()); + } + + const parameterArray: string[] = []; + for (let j = 0; interfaceMethod.parameters && j < interfaceMethod.parameters.length; j++) { + parameterArray.push(interfaceMethod.parameters[j].getText()); + } + + let methodText = methodName; + if (typeParameterArray.length > 0) { + methodText += "<"; + } + + for (let k = 0; k < typeParameterArray.length; k++) { + methodText += typeParameterArray[k]; + if (k !== typeParameterArray.length - 1) { + methodText += ","; + } + } + + if (typeParameterArray.length > 0) { + methodText += ">"; + } + + methodText += "("; + for (let k = 0; k < parameterArray.length; k++) { + methodText += parameterArray[k]; + if (k !== parameterArray.length - 1) { + methodText += ","; + } + } + + methodText += `)`; + if (interfaceMethod.type) { + methodText += ":" + interfaceMethod.type.getText(); + } + + methodText += `{${newLineCharacter}${methodBody}${newLineCharacter}`; + methodText = isReference ? methodText.concat(`},${newLineCharacter}`) : methodText.concat(`}${newLineCharacter}`); + + textChanges.push({ newText: methodText, span: { start: startPos, length: 0 } }); + trackingAddedMembers.push(interfaceMethod.name.getText()); + } + } + + export function getOpenBraceEnd(constructor: ConstructorDeclaration, sourceFile: SourceFile) { + // First token is the open curly, this is where we want to put the 'super' call. + return constructor.body.getFirstToken(sourceFile).getEnd(); + } }