Support static properties
This commit is contained in:
parent
6e86596a73
commit
fd9fb8f9bc
|
@ -1,4 +1,4 @@
|
|||
/* @internal */
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.Property_0_does_not_exist_on_type_1.code],
|
||||
|
@ -13,22 +13,27 @@ namespace ts.codefix {
|
|||
// this.missing = 1;
|
||||
// ^^^^^^^
|
||||
const token = getTokenAtPosition(sourceFile, start);
|
||||
|
||||
if (token.kind != SyntaxKind.Identifier) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const classDeclaration = getContainingClass(token);
|
||||
if (!classDeclaration) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!isPropertyAccessExpression(token.parent) || token.parent.expression.kind !== SyntaxKind.ThisKeyword) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return isInJavaScriptFile(sourceFile) ? getActionsForAddMissingMemberInJavaScriptFile() : getActionsForAddMissingMemberInTypeScriptFile();
|
||||
const classMemberDeclaration = getThisContainer(token, /*includeArrowFunctions*/ false);
|
||||
if (!isClassElement(classMemberDeclaration)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const classDeclaration = <ClassLikeDeclaration>classMemberDeclaration.parent;
|
||||
if (!classDeclaration || !isClassLike(classDeclaration)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const isStatic = hasModifier(getThisContainer(token, /*includeArrowFunctions*/ false), ModifierFlags.Static);
|
||||
|
||||
return isInJavaScriptFile(sourceFile) ? getActionsForAddMissingMemberInJavaScriptFile() : getActionsForAddMissingMemberInTypeScriptFile();
|
||||
|
||||
function getActionsForAddMissingMemberInTypeScriptFile(): CodeAction[] | undefined {
|
||||
let typeString = "any";
|
||||
|
@ -43,47 +48,71 @@ namespace ts.codefix {
|
|||
|
||||
const startPos = classDeclaration.members.pos;
|
||||
|
||||
return [{
|
||||
const actions = [{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: `${token.getFullText(sourceFile)}: ${typeString};`
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: `[name: string]: ${typeString};`
|
||||
newText: `${isStatic ? "static " : ""}${token.getFullText(sourceFile)}: ${typeString};`
|
||||
}]
|
||||
}]
|
||||
}];
|
||||
|
||||
if (!isStatic) {
|
||||
actions.push({
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: `[x: string]: ${typeString};`
|
||||
}]
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
function getActionsForAddMissingMemberInJavaScriptFile(): CodeAction[] | undefined {
|
||||
const classConstructor = getFirstConstructorWithBody(classDeclaration);
|
||||
if (!classConstructor) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const memberName = token.getText();
|
||||
const startPos = classConstructor.body.getEnd() - 1;
|
||||
|
||||
return [{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_property_0_in_the_constructor), [memberName]),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: `this.${memberName} = undefined;`
|
||||
if (isStatic) {
|
||||
if (classDeclaration.kind === SyntaxKind.ClassExpression) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const className = classDeclaration.name.getText();
|
||||
|
||||
return [{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_static_property_0), [memberName]),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: classDeclaration.getEnd(), length: 0 },
|
||||
newText: `${context.newLineCharacter}${className}.${memberName} = undefined;${context.newLineCharacter}`
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}];
|
||||
}];
|
||||
}
|
||||
else {
|
||||
const classConstructor = getFirstConstructorWithBody(classDeclaration);
|
||||
if (!classConstructor) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return [{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_property_0_in_the_constructor), [memberName]),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: classConstructor.body.getEnd() - 1, length: 0 },
|
||||
newText: `this.${memberName} = undefined;${context.newLineCharacter}`
|
||||
}]
|
||||
}]
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
tests/cases/fourslash/codeFixAddMissingMember.ts
Normal file
14
tests/cases/fourslash/codeFixAddMissingMember.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////[|class C {
|
||||
//// method() {
|
||||
//// this.foo = 10;
|
||||
//// }
|
||||
////}|]
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
foo: number;
|
||||
method() {
|
||||
this.foo = 10;
|
||||
}
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
|
14
tests/cases/fourslash/codeFixAddMissingMember2.ts
Normal file
14
tests/cases/fourslash/codeFixAddMissingMember2.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////[|class C {
|
||||
//// method() {
|
||||
//// this.foo = 10;
|
||||
//// }
|
||||
////}|]
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
[x:string]: number;
|
||||
method() {
|
||||
this.foo = 10;
|
||||
}
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 1);
|
14
tests/cases/fourslash/codeFixAddMissingMember3.ts
Normal file
14
tests/cases/fourslash/codeFixAddMissingMember3.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////[|class C {
|
||||
//// static method() {
|
||||
//// this.foo = 10;
|
||||
//// }
|
||||
////}|]
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
static foo: number;
|
||||
static method() {
|
||||
this.foo = 10;
|
||||
}
|
||||
}`);
|
22
tests/cases/fourslash/codeFixAddMissingMember4.ts
Normal file
22
tests/cases/fourslash/codeFixAddMissingMember4.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @checkJs: true
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: a.js
|
||||
////[|class C {
|
||||
//// constructor() {
|
||||
//// }
|
||||
//// method() {
|
||||
//// this.foo === 10;
|
||||
//// }
|
||||
////}|]
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
constructor() {
|
||||
this.foo = undefined;
|
||||
}
|
||||
method() {
|
||||
this.foo === 10;
|
||||
}
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
|
19
tests/cases/fourslash/codeFixAddMissingMember5.ts
Normal file
19
tests/cases/fourslash/codeFixAddMissingMember5.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @checkJs: true
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: a.js
|
||||
////[|class C {
|
||||
//// static method() {
|
||||
//// ()=>{ this.foo === 10 };
|
||||
//// }
|
||||
////}
|
||||
////|]
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
static method() {
|
||||
()=>{ this.foo === 10 };
|
||||
}
|
||||
}
|
||||
C.foo = undefined;`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
|
18
tests/cases/fourslash/codeFixAddMissingMember6.ts
Normal file
18
tests/cases/fourslash/codeFixAddMissingMember6.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @checkJs: true
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: a.js
|
||||
////[|class C {
|
||||
//// constructor() {
|
||||
//// }
|
||||
//// prop = ()=>{ this.foo === 10 };
|
||||
////}|]
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
constructor() {
|
||||
this.foo = undefined;
|
||||
}
|
||||
prop = ()=>{ this.foo === 10 };
|
||||
}`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 0);
|
15
tests/cases/fourslash/codeFixAddMissingMember7.ts
Normal file
15
tests/cases/fourslash/codeFixAddMissingMember7.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @checkJs: true
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: a.js
|
||||
////[|class C {
|
||||
//// static p = ()=>{ this.foo === 10 };
|
||||
////}
|
||||
////|]
|
||||
|
||||
verify.rangeAfterCodeFix(`class C {
|
||||
static p = ()=>{ this.foo === 10 };
|
||||
}
|
||||
C.foo = undefined;`, /*includeWhiteSpace*/false, /*errorCode*/ undefined, /*index*/ 2);
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
verify.rangeAfterCodeFix(`
|
||||
class A {
|
||||
[name: string]: number;
|
||||
[x: string]: number;
|
||||
|
||||
constructor() {
|
||||
this.x = 10;
|
||||
|
|
Loading…
Reference in a new issue