mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-19 08:24:15 -06:00
Api Changes and simple superfixes
This commit is contained in:
parent
269b828538
commit
94ea825f95
53
src/services/codefixes/codeFixProvider.ts
Normal file
53
src/services/codefixes/codeFixProvider.ts
Normal file
@ -0,0 +1,53 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export interface CodeFix {
|
||||
name: string;
|
||||
errorCodes: string[];
|
||||
getCodeActions(context: CodeFixContext): CodeAction[];
|
||||
}
|
||||
|
||||
export interface CodeFixContext {
|
||||
errorCode: string;
|
||||
sourceFile: SourceFile;
|
||||
span: TextSpan;
|
||||
checker: TypeChecker;
|
||||
newLineCharacter: string;
|
||||
}
|
||||
|
||||
export namespace codeFix {
|
||||
const codeFixes: Map<CodeFix[]> = {};
|
||||
|
||||
export function registerCodeFix(action: CodeFix) {
|
||||
forEach(action.errorCodes, error => {
|
||||
let fixes = codeFixes[error];
|
||||
if (!fixes) {
|
||||
fixes = [];
|
||||
codeFixes[error] = fixes;
|
||||
}
|
||||
fixes.push(action);
|
||||
});
|
||||
}
|
||||
|
||||
export class CodeFixProvider {
|
||||
public static getSupportedErrorCodes() {
|
||||
return getKeys(codeFixes);
|
||||
}
|
||||
|
||||
public getFixes(context: CodeFixContext): CodeAction[] {
|
||||
const fixes = codeFixes[context.errorCode];
|
||||
let allActions: CodeAction[] = [];
|
||||
|
||||
Debug.assert(fixes && fixes.length > 0, "No fixes found for error: '${errorCode}'.");
|
||||
|
||||
forEach(fixes, f => {
|
||||
const actions = f.getCodeActions(context);
|
||||
if (actions && actions.length > 0) {
|
||||
allActions = allActions.concat(actions);
|
||||
}
|
||||
});
|
||||
|
||||
return allActions;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
6
src/services/codefixes/references.ts
Normal file
6
src/services/codefixes/references.ts
Normal file
@ -0,0 +1,6 @@
|
||||
///<reference path='..\services.ts' />
|
||||
///<reference path='codeFixProvider.ts' />
|
||||
///<reference path='superFixes.ts' />
|
||||
///<reference path='unusedIdentifierFixes.ts' />
|
||||
///<reference path='changeExtendsToImplementsFix.ts' />
|
||||
///<reference path='interfaceFixes.ts' />
|
||||
65
src/services/codefixes/superFixes.ts
Normal file
65
src/services/codefixes/superFixes.ts
Normal file
@ -0,0 +1,65 @@
|
||||
/* @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({
|
||||
name: "AddMissingSuperCallFix",
|
||||
errorCodes: ["TS2377"],
|
||||
getCodeActions: (context: CodeFixContext) => {
|
||||
const sourceFile = context.sourceFile;
|
||||
const token = getTokenAtPosition(sourceFile, context.span.start);
|
||||
Debug.assert(token.kind === SyntaxKind.ConstructorKeyword, "Failed to find the constructor.");
|
||||
|
||||
const newPosition = getOpenBraceEnd(<ConstructorDeclaration>token.parent, sourceFile);
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call),
|
||||
changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "super();", span: { start: newPosition, length: 0 } }] }]
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
registerCodeFix({
|
||||
name: "MakeSuperCallTheFirstStatementInTheConstructor",
|
||||
errorCodes: ["TS17009"],
|
||||
getCodeActions: (context: CodeFixContext) => {
|
||||
const sourceFile = context.sourceFile;
|
||||
|
||||
const token = getTokenAtPosition(sourceFile, context.span.start);
|
||||
const constructor = getContainingFunction(token);
|
||||
Debug.assert(constructor.kind === SyntaxKind.Constructor, "Failed to find the constructor.");
|
||||
|
||||
const superCall = findSuperCall((<ConstructorDeclaration>constructor).body);
|
||||
Debug.assert(!!superCall, "Failed to find super call.");
|
||||
|
||||
const newPosition = getOpenBraceEnd(<ConstructorDeclaration>constructor, sourceFile);
|
||||
const changes = [{
|
||||
fileName: sourceFile.fileName, textChanges: [{
|
||||
newText: superCall.getText(sourceFile),
|
||||
span: { start: newPosition, length: 0 }
|
||||
},
|
||||
{
|
||||
newText: "",
|
||||
span: { start: superCall.getStart(sourceFile), length: superCall.getWidth(sourceFile) }
|
||||
}]
|
||||
}];
|
||||
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Make_super_call_the_first_statement_in_the_constructor),
|
||||
changes
|
||||
}];
|
||||
|
||||
function findSuperCall(n: Node): Node {
|
||||
if (n.kind === SyntaxKind.ExpressionStatement && isSuperCallExpression((<ExpressionStatement>n).expression)) {
|
||||
return n;
|
||||
}
|
||||
if (isFunctionLike(n)) {
|
||||
return undefined;
|
||||
}
|
||||
return forEachChild(n, findSuperCall);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -11,6 +11,7 @@
|
||||
/// <reference path='jsTyping.ts' />
|
||||
/// <reference path='formatting\formatting.ts' />
|
||||
/// <reference path='formatting\smartIndenter.ts' />
|
||||
/// <reference path='codefixes\references.ts' />
|
||||
|
||||
namespace ts {
|
||||
/** The version of the language service API */
|
||||
@ -1237,6 +1238,8 @@ namespace ts {
|
||||
|
||||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
|
||||
|
||||
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: string[]): CodeAction[];
|
||||
|
||||
getEmitOutput(fileName: string): EmitOutput;
|
||||
|
||||
getProgram(): Program;
|
||||
@ -1283,6 +1286,18 @@ namespace ts {
|
||||
newText: string;
|
||||
}
|
||||
|
||||
export interface FileTextChanges {
|
||||
fileName: string;
|
||||
textChanges: TextChange[];
|
||||
}
|
||||
|
||||
export interface CodeAction {
|
||||
/** Description of the code action to display in the UI of the editor */
|
||||
description: string;
|
||||
/** Text changes to apply to each file as part of the code action */
|
||||
changes: FileTextChanges[];
|
||||
}
|
||||
|
||||
export interface TextInsertion {
|
||||
newText: string;
|
||||
/** The position in newText the caret should point to after the insertion. */
|
||||
@ -1886,9 +1901,13 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
// Cache host information about script should be refreshed
|
||||
export function getSupportedCodeFixes() {
|
||||
return codeFix.CodeFixProvider.getSupportedErrorCodes();
|
||||
}
|
||||
|
||||
// Cache host information about script Should be refreshed
|
||||
// at each language service public entry point, since we don't know when
|
||||
// set of scripts handled by the host changes.
|
||||
// the set of scripts handled by the host changes.
|
||||
class HostCache {
|
||||
private fileNameToEntry: FileMap<HostFileInformation>;
|
||||
private _compilationSettings: CompilerOptions;
|
||||
@ -3022,6 +3041,7 @@ namespace ts {
|
||||
documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService {
|
||||
|
||||
const syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host);
|
||||
const codeFixProvider: codeFix.CodeFixProvider = new codeFix.CodeFixProvider();
|
||||
let ruleProvider: formatting.RulesProvider;
|
||||
let program: Program;
|
||||
let lastProjectVersion: string;
|
||||
@ -7832,6 +7852,30 @@ namespace ts {
|
||||
return [];
|
||||
}
|
||||
|
||||
function getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: string[]): CodeAction[] {
|
||||
synchronizeHostData();
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
const checker = program.getTypeChecker();
|
||||
let allFixes: CodeAction[] = [];
|
||||
|
||||
forEach(errorCodes, error => {
|
||||
const context = {
|
||||
errorCode: error,
|
||||
sourceFile: sourceFile,
|
||||
span: { start, length: end - start },
|
||||
checker: checker,
|
||||
newLineCharacter: getNewLineOrDefaultFromHost(host)
|
||||
};
|
||||
|
||||
const fixes = codeFixProvider.getFixes(context);
|
||||
if (fixes) {
|
||||
allFixes = allFixes.concat(fixes);
|
||||
}
|
||||
});
|
||||
|
||||
return allFixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if position points to a valid position to add JSDoc comments, and if so,
|
||||
* returns the appropriate template. Otherwise returns an empty string.
|
||||
@ -8302,6 +8346,7 @@ namespace ts {
|
||||
getFormattingEditsAfterKeystroke,
|
||||
getDocCommentTemplateAtPosition,
|
||||
isValidBraceCompletionAtPosition,
|
||||
getCodeFixesAtPosition,
|
||||
getEmitOutput,
|
||||
getNonBoundSourceFile,
|
||||
getProgram
|
||||
|
||||
@ -240,6 +240,8 @@ namespace ts {
|
||||
*/
|
||||
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): string;
|
||||
|
||||
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: string): string;
|
||||
|
||||
getEmitOutput(fileName: string): string;
|
||||
getEmitOutputObject(fileName: string): EmitOutput;
|
||||
}
|
||||
@ -255,6 +257,7 @@ namespace ts {
|
||||
getTSConfigFileInfo(fileName: string, sourceText: IScriptSnapshot): string;
|
||||
getDefaultCompilationSettings(): string;
|
||||
discoverTypings(discoverTypingsJson: string): string;
|
||||
getSupportedCodeFixes(): string;
|
||||
}
|
||||
|
||||
function logInternalError(logger: Logger, err: Error) {
|
||||
@ -901,6 +904,16 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
public getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: string): string {
|
||||
return this.forwardJSONCall(
|
||||
`getCodeFixesAtPosition( '${fileName}', ${start}, ${end}, ${errorCodes}')`,
|
||||
() => {
|
||||
const localErrors: string[] = JSON.parse(errorCodes);
|
||||
return this.languageService.getCodeFixesAtPosition(fileName, start, end, localErrors);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/// NAVIGATE TO
|
||||
|
||||
/** Return a list of symbols that are interesting to navigate to */
|
||||
@ -1109,6 +1122,12 @@ namespace ts {
|
||||
info.compilerOptions);
|
||||
});
|
||||
}
|
||||
|
||||
public getSupportedCodeFixes(): string {
|
||||
return this.forwardJSONCall("getSupportedCodeFixes()",
|
||||
() => getSupportedCodeFixes()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class TypeScriptServicesFactory implements ShimFactory {
|
||||
|
||||
@ -52,6 +52,9 @@
|
||||
"formatting/rulesMap.ts",
|
||||
"formatting/rulesProvider.ts",
|
||||
"formatting/smartIndenter.ts",
|
||||
"formatting/tokenRange.ts"
|
||||
"formatting/tokenRange.ts",
|
||||
"codeFixes/codeFixProvider.ts",
|
||||
"codeFixes/references.ts",
|
||||
"codeFixes/superFixes.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user