diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 0905963541d..ea067001377 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4026,5 +4026,101 @@ "Add definite assignment assertion to property '{0}'": { "category": "Message", "code": 95020 + }, + "Add all missing members": { + "category": "Message", + "code": 95022 + }, + "Infer all types from usage": { + "category": "Message", + "code": 95023 + }, + "Delete all unused declarations": { + "category": "Message", + "code": 95024 + }, + "Prefix all unused declarations with '_' where possible": { + "category": "Message", + "code": 95025 + }, + "Fix all detected spelling errors": { + "category": "Message", + "code": 95026 + }, + "Add initializers to all uninitialized properties": { + "category": "Message", + "code": 95027 + }, + "Add definite assignment assertions to all uninitialized properties": { + "category": "Message", + "code": 95028 + }, + "Add undefined type to all uninitialized properties": { + "category": "Message", + "code": 95029 + }, + "Change all jsdoc-style types to TypeScript": { + "category": "Message", + "code": 95030 + }, + "Change all jsdoc-style types to TypeScript (and add '| undefined' to nullable types)": { + "category": "Message", + "code": 95031 + }, + "Implement all unimplemented interfaces": { + "category": "Message", + "code": 95032 + }, + "Install all missing types packages": { + "category": "Message", + "code": 95033 + }, + "Rewrite all as indexed access types": { + "category": "Message", + "code": 95034 + }, + "Convert all to default imports": { + "category": "Message", + "code": 95035 + }, + "Make all 'super()' calls the first statement in their constructor": { + "category": "Message", + "code": 95036 + }, + "Add 'this.' to all unresolved variables matching a member name": { + "category": "Message", + "code": 95037 + }, + "Change all extended interfaces to 'implements'": { + "category": "Message", + "code": 95038 + }, + "Add all missing super calls": { + "category": "Message", + "code": 95039 + }, + "Implement all inherited abstract classes": { + "category": "Message", + "code": 95040 + }, + "Add all missing 'async' modifiers": { + "category": "Message", + "code": 95041 + }, + "Add '@ts-ignore' to all error messages": { + "category": "Message", + "code": 95042 + }, + "Annotate everything with types from JSDoc": { + "category": "Message", + "code": 95043 + }, + "Add '()' to all uncalled decorators": { + "category": "Message", + "code": 95044 + }, + "Convert all constructor functions to classes": { + "category": "Message", + "code": 95045 } } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 4e1c44ae01c..17b3d52c040 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2457,12 +2457,14 @@ Actual: ${stringify(fullActual)}`); this.verifyRangeIs(expectedText, includeWhiteSpace); } - public verifyCodeFixAll(options: FourSlashInterface.VerifyCodeFixAllOptions): void { - const { fixId, newFileContent } = options; - const fixIds = ts.mapDefined(this.getCodeFixes(this.activeFile.fileName), a => a.fixId); - ts.Debug.assert(ts.contains(fixIds, fixId), "No available code fix has that group id.", () => `Expected '${fixId}'. Available action ids: ${fixIds}`); + public verifyCodeFixAll({ fixId, fixAllDescription, newFileContent, commands: expectedCommands }: FourSlashInterface.VerifyCodeFixAllOptions): void { + const fixWithId = ts.find(this.getCodeFixes(this.activeFile.fileName), a => a.fixId === fixId); + ts.Debug.assert(fixWithId !== undefined, "No available code fix has that group id.", () => + `Expected '${fixId}'. Available action ids: ${ts.mapDefined(this.getCodeFixes(this.activeFile.fileName), a => a.fixId)}`); + ts.Debug.assertEqual(fixWithId.fixAllDescription, fixAllDescription); + const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.defaultPreferences); - assert.deepEqual(commands, options.commands); + assert.deepEqual(commands, expectedCommands); assert(changes.every(c => c.fileName === this.activeFile.fileName), "TODO: support testing codefixes that touch multiple files"); this.applyChanges(changes); this.verifyCurrentFileContent(newFileContent); @@ -4661,6 +4663,7 @@ namespace FourSlashInterface { export interface VerifyCodeFixAllOptions { fixId: string; + fixAllDescription: string; newFileContent: string; commands: ReadonlyArray<{}>; } diff --git a/src/server/client.ts b/src/server/client.ts index 1a0912d378c..98fb130dbb3 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -557,7 +557,7 @@ namespace ts.server { const request = this.processRequest(CommandNames.GetCodeFixes, args); const response = this.processResponse(request); - return response.body.map(({ description, changes, fixId }) => ({ description, changes: this.convertChanges(changes, file), fixId })); + return response.body.map(({ description, changes, fixId, fixAllDescription }) => ({ description, changes: this.convertChanges(changes, file), fixId, fixAllDescription })); } getCombinedCodeFix = notImplemented; diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 9e179db8e5e..3f0ce3b6d40 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -1701,6 +1701,8 @@ namespace ts.server.protocol { * This may be omitted to indicate that the code fix can't be applied in a group. */ fixId?: {}; + /** Should be present if and only if 'fixId' is. */ + fixAllDescription?: string; } /** diff --git a/src/server/session.ts b/src/server/session.ts index 4d9c296f6a9..4d39b4d0cf9 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1723,9 +1723,9 @@ namespace ts.server { return { startPosition, endPosition }; } - private mapCodeAction(project: Project, { description, changes: unmappedChanges, commands, fixId }: CodeFixAction): protocol.CodeFixAction { + private mapCodeAction(project: Project, { description, changes: unmappedChanges, commands, fixId, fixAllDescription }: CodeFixAction): protocol.CodeFixAction { const changes = unmappedChanges.map(change => this.mapTextChangesToCodeEditsUsingScriptinfo(change, project.getScriptInfoForNormalizedPath(toNormalizedPath(change.fileName)))); - return { description, changes, commands, fixId }; + return { description, changes, commands, fixId, fixAllDescription }; } private mapTextChangesToCodeEdits(project: Project, textChanges: ReadonlyArray): protocol.FileCodeEdits[] { diff --git a/src/services/codeFixProvider.ts b/src/services/codeFixProvider.ts index 74d3487a74c..291f8fd1d66 100644 --- a/src/services/codeFixProvider.ts +++ b/src/services/codeFixProvider.ts @@ -27,6 +27,25 @@ namespace ts { const codeFixRegistrations: CodeFixRegistration[][] = []; const fixIdToRegistration = createMap(); + type DiagnosticAndArguments = DiagnosticMessage | [DiagnosticMessage, string] | [DiagnosticMessage, string, string]; + function diagnosticToString(diag: DiagnosticAndArguments): string { + return isArray(diag) + ? formatStringFromArgs(getLocaleSpecificMessage(diag[0]), diag.slice(1) as ReadonlyArray) + : getLocaleSpecificMessage(diag); + } + + export function createCodeFixActionNoFixId(changes: FileTextChanges[], description: DiagnosticAndArguments) { + return createCodeFixActionWorker(diagnosticToString(description), changes, /*fixId*/ undefined, /*fixAllDescription*/ undefined); + } + + export function createCodeFixAction(changes: FileTextChanges[], description: DiagnosticAndArguments, fixId: {}, fixAllDescription: DiagnosticAndArguments, command?: CodeActionCommand): CodeFixAction { + return createCodeFixActionWorker(diagnosticToString(description), changes, fixId, diagnosticToString(fixAllDescription), command); + } + + function createCodeFixActionWorker(description: string, changes: FileTextChanges[], fixId?: {}, fixAllDescription?: string, command?: CodeActionCommand): CodeFixAction { + return { description, changes, fixId, fixAllDescription, commands: command ? [command] : undefined }; + } + export function registerCodeFix(reg: CodeFixRegistration) { for (const error of reg.errorCodes) { let registrations = codeFixRegistrations[error]; diff --git a/src/services/codefixes/addMissingInvocationForDecorator.ts b/src/services/codefixes/addMissingInvocationForDecorator.ts index d063df87be4..7b8a7d05fe7 100644 --- a/src/services/codefixes/addMissingInvocationForDecorator.ts +++ b/src/services/codefixes/addMissingInvocationForDecorator.ts @@ -6,7 +6,7 @@ namespace ts.codefix { errorCodes, getCodeActions: (context) => { const changes = textChanges.ChangeTracker.with(context, t => makeChange(t, context.sourceFile, context.span.start)); - return [{ description: getLocaleSpecificMessage(Diagnostics.Call_decorator_expression), changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Call_decorator_expression, fixId, Diagnostics.Add_to_all_uncalled_decorators)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file!, diag.start!)), diff --git a/src/services/codefixes/annotateWithTypeFromJSDoc.ts b/src/services/codefixes/annotateWithTypeFromJSDoc.ts index 20fc3a9c601..5edbab01450 100644 --- a/src/services/codefixes/annotateWithTypeFromJSDoc.ts +++ b/src/services/codefixes/annotateWithTypeFromJSDoc.ts @@ -7,9 +7,8 @@ namespace ts.codefix { getCodeActions(context) { const decl = getDeclaration(context.sourceFile, context.span.start); if (!decl) return; - const description = getLocaleSpecificMessage(Diagnostics.Annotate_with_type_from_JSDoc); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, decl)); - return [{ description, changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Annotate_with_type_from_JSDoc, fixId, Diagnostics.Annotate_everything_with_types_from_JSDoc)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index d63837e7dd4..a4386ab07f1 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -6,7 +6,7 @@ namespace ts.codefix { errorCodes, getCodeActions(context: CodeFixContext) { const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, context.span.start, context.program.getTypeChecker())); - return [{ description: getLocaleSpecificMessage(Diagnostics.Convert_function_to_an_ES2015_class), changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Convert_function_to_an_ES2015_class, fixId, Diagnostics.Convert_all_constructor_functions_to_classes)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => doChange(changes, err.file!, err.start, context.program.getTypeChecker())), diff --git a/src/services/codefixes/convertToEs6Module.ts b/src/services/codefixes/convertToEs6Module.ts index 23444af22ff..b8c78d57827 100644 --- a/src/services/codefixes/convertToEs6Module.ts +++ b/src/services/codefixes/convertToEs6Module.ts @@ -3,7 +3,6 @@ namespace ts.codefix { registerCodeFix({ errorCodes: [Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module.code], getCodeActions(context) { - const description = getLocaleSpecificMessage(Diagnostics.Convert_to_ES6_module); const { sourceFile, program } = context; const changes = textChanges.ChangeTracker.with(context, changes => { const moduleExportsChangedToDefault = convertFileToEs6Module(sourceFile, program.getTypeChecker(), changes, program.getCompilerOptions().target); @@ -14,7 +13,7 @@ namespace ts.codefix { } }); // No support for fix-all since this applies to the whole file at once anyway. - return [{ description, changes, fixId: undefined }]; + return [createCodeFixActionNoFixId(changes, Diagnostics.Convert_to_ES6_module)]; }, }); diff --git a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts index de4498035be..f47b65aad90 100644 --- a/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts +++ b/src/services/codefixes/correctQualifiedNameToIndexedAccessType.ts @@ -8,8 +8,8 @@ namespace ts.codefix { const qualifiedName = getQualifiedName(context.sourceFile, context.span.start); if (!qualifiedName) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, context.sourceFile, qualifiedName)); - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Rewrite_as_the_indexed_access_type_0), [`${qualifiedName.left.text}["${qualifiedName.right.text}"]`]); - return [{ description, changes, fixId }]; + const newText = `${qualifiedName.left.text}["${qualifiedName.right.text}"]`; + return [createCodeFixAction(changes, [Diagnostics.Rewrite_as_the_indexed_access_type_0, newText], fixId, Diagnostics.Rewrite_all_as_indexed_access_types)]; }, fixIds: [fixId], getAllCodeActions: (context) => codeFixAll(context, errorCodes, (changes, diag) => { diff --git a/src/services/codefixes/disableJsDiagnostics.ts b/src/services/codefixes/disableJsDiagnostics.ts index 2d82a198ce9..c53c35c5f81 100644 --- a/src/services/codefixes/disableJsDiagnostics.ts +++ b/src/services/codefixes/disableJsDiagnostics.ts @@ -16,23 +16,18 @@ namespace ts.codefix { } const fixes: CodeFixAction[] = [ - { - description: getLocaleSpecificMessage(Diagnostics.Disable_checking_for_this_file), - changes: [createFileTextChanges(sourceFile.fileName, [ + // fixId unnecessary because adding `// @ts-nocheck` even once will ignore every error in the file. + createCodeFixActionNoFixId( + [createFileTextChanges(sourceFile.fileName, [ createTextChange(sourceFile.checkJsDirective ? createTextSpanFromBounds(sourceFile.checkJsDirective.pos, sourceFile.checkJsDirective.end) : createTextSpan(0, 0), `// @ts-nocheck${getNewLineOrDefaultFromHost(host, formatContext.options)}`), ])], - // fixId unnecessary because adding `// @ts-nocheck` even once will ignore every error in the file. - fixId: undefined, - }]; + Diagnostics.Disable_checking_for_this_file), + ]; if (textChanges.isValidLocationToAddComment(sourceFile, span.start)) { - fixes.unshift({ - description: getLocaleSpecificMessage(Diagnostics.Ignore_this_error_message), - changes: textChanges.ChangeTracker.with(context, t => makeChange(t, sourceFile, span.start)), - fixId, - }); + fixes.unshift(createCodeFixAction(textChanges.ChangeTracker.with(context, t => makeChange(t, sourceFile, span.start)), Diagnostics.Ignore_this_error_message, fixId, Diagnostics.Add_ts_ignore_to_all_error_messages)); } return fixes; diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index b315dd0659f..d8df415a4de 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -97,9 +97,8 @@ namespace ts.codefix { function getActionsForAddMissingMemberInJavaScriptFile(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): CodeFixAction | undefined { const changes = textChanges.ChangeTracker.with(context, t => addMissingMemberInJs(t, classDeclarationSourceFile, classDeclaration, tokenName, makeStatic)); - if (changes.length === 0) return undefined; - const description = formatStringFromArgs(getLocaleSpecificMessage(makeStatic ? Diagnostics.Initialize_static_property_0 : Diagnostics.Initialize_property_0_in_the_constructor), [tokenName]); - return { description, changes, fixId }; + return changes.length === 0 ? undefined + : createCodeFixAction(changes, [makeStatic ? Diagnostics.Initialize_static_property_0 : Diagnostics.Initialize_property_0_in_the_constructor, tokenName], fixId, Diagnostics.Add_all_missing_members); } function addMissingMemberInJs(changeTracker: textChanges.ChangeTracker, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): void { @@ -143,9 +142,8 @@ namespace ts.codefix { } function createAddPropertyDeclarationAction(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, makeStatic: boolean, tokenName: string, typeNode: TypeNode): CodeFixAction { - const description = formatStringFromArgs(getLocaleSpecificMessage(makeStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0), [tokenName]); const changes = textChanges.ChangeTracker.with(context, t => addPropertyDeclaration(t, classDeclarationSourceFile, classDeclaration, tokenName, typeNode, makeStatic)); - return { description, changes, fixId }; + return createCodeFixAction(changes, [makeStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0, tokenName], fixId, Diagnostics.Add_all_missing_members); } function addPropertyDeclaration(changeTracker: textChanges.ChangeTracker, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, typeNode: TypeNode, makeStatic: boolean): void { @@ -178,7 +176,7 @@ namespace ts.codefix { const changes = textChanges.ChangeTracker.with(context, t => t.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, indexSignature)); // No fixId here because code-fix-all currently only works on adding individual named properties. - return { description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_property_0), [tokenName]), changes, fixId: undefined }; + return createCodeFixActionNoFixId(changes, [Diagnostics.Add_index_signature_for_property_0, tokenName]); } function getActionForMethodDeclaration( @@ -191,9 +189,8 @@ namespace ts.codefix { inJs: boolean, preferences: UserPreferences, ): CodeFixAction | undefined { - const description = formatStringFromArgs(getLocaleSpecificMessage(makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0), [token.text]); const changes = textChanges.ChangeTracker.with(context, t => addMethodDeclaration(t, classDeclarationSourceFile, classDeclaration, token, callExpression, makeStatic, inJs, preferences)); - return { description, changes, fixId }; + return createCodeFixAction(changes, [makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0, token.text], fixId, Diagnostics.Add_all_missing_members); } function addMethodDeclaration( diff --git a/src/services/codefixes/fixAwaitInSyncFunction.ts b/src/services/codefixes/fixAwaitInSyncFunction.ts index 713a25456c0..804910e9a22 100644 --- a/src/services/codefixes/fixAwaitInSyncFunction.ts +++ b/src/services/codefixes/fixAwaitInSyncFunction.ts @@ -12,7 +12,7 @@ namespace ts.codefix { const nodes = getNodes(sourceFile, span.start); if (!nodes) return undefined; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, nodes)); - return [{ description: getLocaleSpecificMessage(Diagnostics.Add_async_modifier_to_containing_function), changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Add_async_modifier_to_containing_function, fixId, Diagnostics.Add_all_missing_async_modifiers)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { diff --git a/src/services/codefixes/fixCannotFindModule.ts b/src/services/codefixes/fixCannotFindModule.ts index 41563e6ca90..89f7a3f7793 100644 --- a/src/services/codefixes/fixCannotFindModule.ts +++ b/src/services/codefixes/fixCannotFindModule.ts @@ -5,38 +5,27 @@ namespace ts.codefix { registerCodeFix({ errorCodes, getCodeActions: context => { - const codeAction = tryGetCodeActionForInstallPackageTypes(context.host, context.sourceFile.fileName, getModuleName(context.sourceFile, context.span.start)); - return codeAction && [{ fixId, ...codeAction }]; + const { host, sourceFile, span: { start } } = context; + const packageName = getTypesPackageNameToInstall(host, sourceFile, start); + return packageName === undefined ? [] + : [createCodeFixAction(/*changes*/ [], [Diagnostics.Install_0, packageName], fixId, Diagnostics.Install_all_missing_types_packages, getCommand(sourceFile.fileName, packageName))]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (_, diag, commands) => { - const pkg = getTypesPackageNameToInstall(context.host, getModuleName(diag.file, diag.start)); + const pkg = getTypesPackageNameToInstall(context.host, diag.file, diag.start); if (pkg) { commands.push(getCommand(diag.file.fileName, pkg)); } }), }); - function getModuleName(sourceFile: SourceFile, pos: number): string { - return cast(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false), isStringLiteral).text; - } - function getCommand(fileName: string, packageName: string): InstallPackageAction { return { type: "install package", file: fileName, packageName }; } - function getTypesPackageNameToInstall(host: LanguageServiceHost, moduleName: string): string | undefined { + function getTypesPackageNameToInstall(host: LanguageServiceHost, sourceFile: SourceFile, pos: number): string | undefined { + const moduleName = cast(getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false), isStringLiteral).text; const { packageName } = getPackageName(moduleName); - // If !registry, registry not available yet, can't do anything. return host.isKnownTypesPackageName(packageName) ? getTypesPackageName(packageName) : undefined; } - - function tryGetCodeActionForInstallPackageTypes(host: LanguageServiceHost, fileName: string, moduleName: string): CodeAction | undefined { - const packageName = getTypesPackageNameToInstall(host, moduleName); - return packageName === undefined ? undefined : { - description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Install_0), [packageName]), - changes: [], - commands: [getCommand(fileName, packageName)], - }; - } } diff --git a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts index cb33d1c1793..3a1443c04bb 100644 --- a/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts +++ b/src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts @@ -11,7 +11,7 @@ namespace ts.codefix { const { program, sourceFile, span } = context; const changes = textChanges.ChangeTracker.with(context, t => addMissingMembers(getClass(sourceFile, span.start), sourceFile, program.getTypeChecker(), t, context.preferences)); - return changes.length === 0 ? undefined : [{ description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class), changes, fixId }]; + return changes.length === 0 ? undefined : [createCodeFixAction(changes, Diagnostics.Implement_inherited_abstract_class, fixId, Diagnostics.Implement_all_inherited_abstract_classes)]; }, fixIds: [fixId], getAllCodeActions: context => { diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index 38cedbb2ce4..695bbdda4b0 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -11,9 +11,7 @@ namespace ts.codefix { const checker = program.getTypeChecker(); return mapDefined(getClassImplementsHeritageClauseElements(classDeclaration), implementedTypeNode => { const changes = textChanges.ChangeTracker.with(context, t => addMissingDeclarations(checker, implementedTypeNode, sourceFile, classDeclaration, t, context.preferences)); - if (changes.length === 0) return undefined; - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Implement_interface_0), [implementedTypeNode.getText()]); - return { description, changes, fixId }; + return changes.length === 0 ? undefined : createCodeFixAction(changes, [Diagnostics.Implement_interface_0, implementedTypeNode.getText(sourceFile)], fixId, Diagnostics.Implement_all_unimplemented_interfaces); }); }, fixIds: [fixId], diff --git a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts index 8d47e74d8a4..d9c98747286 100644 --- a/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts +++ b/src/services/codefixes/fixClassSuperMustPrecedeThisAccess.ts @@ -10,7 +10,7 @@ namespace ts.codefix { if (!nodes) return undefined; const { constructor, superCall } = nodes; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, constructor, superCall)); - return [{ description: getLocaleSpecificMessage(Diagnostics.Make_super_call_the_first_statement_in_the_constructor), changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Make_super_call_the_first_statement_in_the_constructor, fixId, Diagnostics.Make_all_super_calls_the_first_statement_in_their_constructor)]; }, fixIds: [fixId], getAllCodeActions(context) { diff --git a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts index 8fe2e8458a8..31aa4fcedae 100644 --- a/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts +++ b/src/services/codefixes/fixConstructorForDerivedNeedSuperCall.ts @@ -8,7 +8,7 @@ namespace ts.codefix { const { sourceFile, span } = context; const ctr = getNode(sourceFile, span.start); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, ctr)); - return [{ description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call), changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Add_missing_super_call, fixId, Diagnostics.Add_all_missing_super_calls)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => diff --git a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts index 92d65299489..381a8228c0d 100644 --- a/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts +++ b/src/services/codefixes/fixExtendsInterfaceBecomesImplements.ts @@ -10,7 +10,7 @@ namespace ts.codefix { if (!nodes) return undefined; const { extendsToken, heritageClauses } = nodes; const changes = textChanges.ChangeTracker.with(context, t => doChanges(t, sourceFile, extendsToken, heritageClauses)); - return [{ description: getLocaleSpecificMessage(Diagnostics.Change_extends_to_implements), changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Change_extends_to_implements, fixId, Diagnostics.Change_all_extended_interfaces_to_implements)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { diff --git a/src/services/codefixes/fixForgottenThisPropertyAccess.ts b/src/services/codefixes/fixForgottenThisPropertyAccess.ts index 10933b031e5..2cf7e2143a3 100644 --- a/src/services/codefixes/fixForgottenThisPropertyAccess.ts +++ b/src/services/codefixes/fixForgottenThisPropertyAccess.ts @@ -11,7 +11,7 @@ namespace ts.codefix { return undefined; } const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, token)); - return [{ description: getLocaleSpecificMessage(Diagnostics.Add_this_to_unresolved_variable), changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Add_this_to_unresolved_variable, fixId, Diagnostics.Add_this_to_all_unresolved_variables_matching_a_member_name)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { diff --git a/src/services/codefixes/fixInvalidImportSyntax.ts b/src/services/codefixes/fixInvalidImportSyntax.ts index fd66a9db37c..84bd9867c70 100644 --- a/src/services/codefixes/fixInvalidImportSyntax.ts +++ b/src/services/codefixes/fixInvalidImportSyntax.ts @@ -5,7 +5,7 @@ namespace ts.codefix { getCodeActions: getActionsForInvalidImport }); - function getActionsForInvalidImport(context: CodeFixContext): CodeAction[] | undefined { + function getActionsForInvalidImport(context: CodeFixContext): CodeFixAction[] | undefined { const sourceFile = context.sourceFile; // This is the whole import statement, eg: @@ -19,11 +19,11 @@ namespace ts.codefix { return getCodeFixesForImportDeclaration(context, node); } - function getCodeFixesForImportDeclaration(context: CodeFixContext, node: ImportDeclaration) { + function getCodeFixesForImportDeclaration(context: CodeFixContext, node: ImportDeclaration): CodeFixAction[] { const sourceFile = getSourceFileOfNode(node); const namespace = getNamespaceDeclarationNode(node) as NamespaceImport; const opts = context.program.getCompilerOptions(); - const variations: CodeAction[] = []; + const variations: CodeFixAction[] = []; // import Bluebird from "bluebird"; variations.push(createAction(context, sourceFile, node, makeImportDeclaration(namespace.name, /*namedImports*/ undefined, node.moduleSpecifier))); @@ -41,12 +41,9 @@ namespace ts.codefix { return variations; } - function createAction(context: CodeFixContext, sourceFile: SourceFile, node: Node, replacement: Node): CodeAction { + function createAction(context: CodeFixContext, sourceFile: SourceFile, node: Node, replacement: Node): CodeFixAction { const changes = textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, node, replacement)); - return { - description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Replace_import_with_0), [changes[0].textChanges[0].newText]), - changes, - }; + return createCodeFixActionNoFixId(changes, [Diagnostics.Replace_import_with_0, changes[0].textChanges[0].newText]); } registerCodeFix({ @@ -57,7 +54,7 @@ namespace ts.codefix { getCodeActions: getActionsForUsageOfInvalidImport }); - function getActionsForUsageOfInvalidImport(context: CodeFixContext): CodeAction[] | undefined { + function getActionsForUsageOfInvalidImport(context: CodeFixContext): CodeFixAction[] | undefined { const sourceFile = context.sourceFile; const targetKind = Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression; const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start, /*includeJsDocComment*/ false), a => a.kind === targetKind && a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length)) as CallExpression | NewExpression; @@ -69,15 +66,13 @@ namespace ts.codefix { if (!(type.symbol && (type.symbol as TransientSymbol).originatingImport)) { return []; } - const fixes: CodeAction[] = []; + const fixes: CodeFixAction[] = []; const relatedImport = (type.symbol as TransientSymbol).originatingImport; if (!isImportCall(relatedImport)) { addRange(fixes, getCodeFixesForImportDeclaration(context, relatedImport)); } - fixes.push({ - description: getLocaleSpecificMessage(Diagnostics.Use_synthetic_default_member), - changes: textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, expr, createPropertyAccess(expr, "default"), {})), - }); + const changes = textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, expr, createPropertyAccess(expr, "default"), {})); + fixes.push(createCodeFixActionNoFixId(changes, Diagnostics.Use_synthetic_default_member)); return fixes; } } diff --git a/src/services/codefixes/fixJSDocTypes.ts b/src/services/codefixes/fixJSDocTypes.ts index 344d840cc2e..848666b67f0 100644 --- a/src/services/codefixes/fixJSDocTypes.ts +++ b/src/services/codefixes/fixJSDocTypes.ts @@ -12,19 +12,17 @@ namespace ts.codefix { if (!info) return undefined; const { typeNode, type } = info; const original = typeNode.getText(sourceFile); - const actions = [fix(type, fixIdPlain)]; + const actions = [fix(type, fixIdPlain, Diagnostics.Change_all_jsdoc_style_types_to_TypeScript)]; if (typeNode.kind === SyntaxKind.JSDocNullableType) { // for nullable types, suggest the flow-compatible `T | null | undefined` // in addition to the jsdoc/closure-compatible `T | null` - actions.push(fix(checker.getNullableType(type, TypeFlags.Undefined), fixIdNullable)); + actions.push(fix(checker.getNullableType(type, TypeFlags.Undefined), fixIdNullable, Diagnostics.Change_all_jsdoc_style_types_to_TypeScript_and_add_undefined_to_nullable_types)); } return actions; - function fix(type: Type, fixId: string): CodeFixAction { - const newText = checker.typeToString(type); - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_0_to_1), [original, newText]); + function fix(type: Type, fixId: string, fixAllDescription: DiagnosticMessage): CodeFixAction { const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, typeNode, type, checker)); - return { description, changes, fixId }; + return createCodeFixAction(changes, [Diagnostics.Change_0_to_1, original, checker.typeToString(type)], fixId, fixAllDescription); } }, fixIds: [fixIdPlain, fixIdNullable], diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts index 729f14e9ef9..b997c3c4312 100644 --- a/src/services/codefixes/fixSpelling.ts +++ b/src/services/codefixes/fixSpelling.ts @@ -13,8 +13,7 @@ namespace ts.codefix { if (!info) return undefined; const { node, suggestion } = info; const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, node, suggestion)); - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Change_spelling_to_0), [suggestion]); - return [{ description, changes, fixId }]; + return [createCodeFixAction(changes, [Diagnostics.Change_spelling_to_0, suggestion], fixId, Diagnostics.Fix_all_detected_spelling_errors)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { diff --git a/src/services/codefixes/fixStrictClassInitialization.ts b/src/services/codefixes/fixStrictClassInitialization.ts index a5420f2c181..2f51cedbe82 100644 --- a/src/services/codefixes/fixStrictClassInitialization.ts +++ b/src/services/codefixes/fixStrictClassInitialization.ts @@ -52,9 +52,8 @@ namespace ts.codefix { } function getActionForAddMissingDefiniteAssignmentAssertion (context: CodeFixContext, propertyDeclaration: PropertyDeclaration): CodeFixAction { - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_definite_assignment_assertion_to_property_0), [propertyDeclaration.getText()]); const changes = textChanges.ChangeTracker.with(context, t => addDefiniteAssignmentAssertion(t, context.sourceFile, propertyDeclaration)); - return { description, changes, fixId: fixIdAddDefiniteAssignmentAssertions }; + return createCodeFixAction(changes, [Diagnostics.Add_definite_assignment_assertion_to_property_0, propertyDeclaration.getText()], fixIdAddDefiniteAssignmentAssertions, Diagnostics.Add_definite_assignment_assertions_to_all_uninitialized_properties); } function addDefiniteAssignmentAssertion(changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration): void { @@ -71,9 +70,8 @@ namespace ts.codefix { } function getActionForAddMissingUndefinedType (context: CodeFixContext, propertyDeclaration: PropertyDeclaration): CodeFixAction { - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_undefined_type_to_property_0), [propertyDeclaration.name.getText()]); const changes = textChanges.ChangeTracker.with(context, t => addUndefinedType(t, context.sourceFile, propertyDeclaration)); - return { description, changes, fixId: fixIdAddUndefinedType }; + return createCodeFixAction(changes, [Diagnostics.Add_undefined_type_to_property_0, propertyDeclaration.name.getText()], fixIdAddUndefinedType, Diagnostics.Add_undefined_type_to_all_uninitialized_properties); } function addUndefinedType(changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration): void { @@ -82,14 +80,13 @@ namespace ts.codefix { changeTracker.replaceNode(propertyDeclarationSourceFile, propertyDeclaration.type, createUnionTypeNode(types)); } - function getActionForAddMissingInitializer (context: CodeFixContext, propertyDeclaration: PropertyDeclaration): CodeFixAction | undefined { + function getActionForAddMissingInitializer(context: CodeFixContext, propertyDeclaration: PropertyDeclaration): CodeFixAction | undefined { const checker = context.program.getTypeChecker(); const initializer = getInitializer(checker, propertyDeclaration); if (!initializer) return undefined; - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_initializer_to_property_0), [propertyDeclaration.name.getText()]); const changes = textChanges.ChangeTracker.with(context, t => addInitializer(t, context.sourceFile, propertyDeclaration, initializer)); - return { description, changes, fixId: fixIdAddInitializer }; + return createCodeFixAction(changes, [Diagnostics.Add_initializer_to_property_0, propertyDeclaration.name.getText()], fixIdAddInitializer, Diagnostics.Add_initializers_to_all_uninitialized_properties); } function addInitializer (changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration, initializer: Expression): void { diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index 3de5e7e36b0..1fe0107dafb 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -13,9 +13,8 @@ namespace ts.codefix { const { errorCode, sourceFile } = context; const importDecl = tryGetFullImport(sourceFile, context.span.start); if (importDecl) { - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_import_from_0), [showModuleSpecifier(importDecl)]); const changes = textChanges.ChangeTracker.with(context, t => t.deleteNode(sourceFile, importDecl)); - return [{ description, changes, fixId: fixIdDelete }]; + return [createCodeFixAction(changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], fixIdDelete, Diagnostics.Delete_all_unused_declarations)]; } const token = getToken(sourceFile, textSpanEnd(context.span)); @@ -23,14 +22,12 @@ namespace ts.codefix { const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(t, sourceFile, token)); if (deletion.length) { - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), [token.getText()]); - result.push({ description, changes: deletion, fixId: fixIdDelete }); + result.push(createCodeFixAction(deletion, [Diagnostics.Remove_declaration_for_Colon_0, token.getText(sourceFile)], fixIdDelete, Diagnostics.Delete_all_unused_declarations)); } const prefix = textChanges.ChangeTracker.with(context, t => tryPrefixDeclaration(t, errorCode, sourceFile, token)); if (prefix.length) { - const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Prefix_0_with_an_underscore), [token.getText()]); - result.push({ description, changes: prefix, fixId: fixIdPrefix }); + result.push(createCodeFixAction(prefix, [Diagnostics.Prefix_0_with_an_underscore, token.getText(sourceFile)], fixIdPrefix, Diagnostics.Prefix_all_unused_declarations_with_where_possible)); } return result; diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index a22201d0479..95cd84ee620 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -33,10 +33,9 @@ namespace ts.codefix { preferences: UserPreferences; } - function createCodeAction(descriptionDiagnostic: DiagnosticMessage, diagnosticArgs: string[], changes: FileTextChanges[]): CodeFixAction { - const description = formatMessage.apply(undefined, [undefined, descriptionDiagnostic].concat(diagnosticArgs)); + function createCodeAction(descriptionDiagnostic: DiagnosticMessage, diagnosticArgs: [string, string], changes: FileTextChanges[]): CodeFixAction { // TODO: GH#20315 - return { description, changes, fixId: undefined }; + return createCodeFixActionNoFixId(changes, [descriptionDiagnostic, ...diagnosticArgs] as [DiagnosticMessage, string, string]); } function convertToImportCodeFixContext(context: CodeFixContext, symbolToken: Node, symbolName: string): ImportCodeFixContext { @@ -640,13 +639,13 @@ namespace ts.codefix { return createCodeAction(Diagnostics.Change_0_to_1, [symbolName, `${namespacePrefix}.${symbolName}`], changes); } - function getImportCodeActions(context: CodeFixContext): CodeAction[] { + function getImportCodeActions(context: CodeFixContext): CodeFixAction[] { return context.errorCode === Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead.code ? getActionsForUMDImport(context) : getActionsForNonUMDImport(context); } - function getActionsForUMDImport(context: CodeFixContext): CodeAction[] { + function getActionsForUMDImport(context: CodeFixContext): CodeFixAction[] { const token = getTokenAtPosition(context.sourceFile, context.span.start, /*includeJsDocComment*/ false); const checker = context.program.getTypeChecker(); @@ -702,7 +701,7 @@ namespace ts.codefix { } } - function getActionsForNonUMDImport(context: CodeFixContext): CodeAction[] | undefined { + function getActionsForNonUMDImport(context: CodeFixContext): CodeFixAction[] | undefined { // This will always be an Identifier, since the diagnostics we fix only fail on identifiers. const { sourceFile, span, program, cancellationToken } = context; const checker = program.getTypeChecker(); diff --git a/src/services/codefixes/inferFromUsage.ts b/src/services/codefixes/inferFromUsage.ts index a79fa5acc66..8d46bbf4ded 100644 --- a/src/services/codefixes/inferFromUsage.ts +++ b/src/services/codefixes/inferFromUsage.ts @@ -33,10 +33,8 @@ namespace ts.codefix { const token = getTokenAtPosition(sourceFile, start, /*includeJsDocComment*/ false); let declaration!: Declaration; const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken); }); - if (changes.length === 0) return undefined; - const name = getNameOfDeclaration(declaration).getText(); - const description = formatStringFromArgs(getLocaleSpecificMessage(getDiagnostic(errorCode, token)), [name]); - return [{ description, changes, fixId }]; + return changes.length === 0 ? undefined + : [createCodeFixAction(changes, [getDiagnostic(errorCode, token), getNameOfDeclaration(declaration).getText(sourceFile)], fixId, Diagnostics.Infer_all_types_from_usage)]; }, fixIds: [fixId], getAllCodeActions(context) { diff --git a/src/services/codefixes/useDefaultImport.ts b/src/services/codefixes/useDefaultImport.ts index bd0797953b9..7a6a0acfc30 100644 --- a/src/services/codefixes/useDefaultImport.ts +++ b/src/services/codefixes/useDefaultImport.ts @@ -8,9 +8,8 @@ namespace ts.codefix { const { sourceFile, span: { start } } = context; const info = getInfo(sourceFile, start); if (!info) return undefined; - const description = getLocaleSpecificMessage(Diagnostics.Convert_to_default_import); const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, info)); - return [{ description, changes, fixId }]; + return [createCodeFixAction(changes, Diagnostics.Convert_to_default_import, fixId, Diagnostics.Convert_all_to_default_imports)]; }, fixIds: [fixId], getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => { diff --git a/src/services/types.ts b/src/services/types.ts index af496cfeb11..3eb6f5dba2a 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -440,6 +440,7 @@ namespace ts { * This may be omitted to indicate that the code fix can't be applied in a group. */ fixId?: {}; + fixAllDescription?: string; } export interface CombinedCodeActions { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index c344b31b1fc..7a121848f47 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4242,6 +4242,7 @@ declare namespace ts { * This may be omitted to indicate that the code fix can't be applied in a group. */ fixId?: {}; + fixAllDescription?: string; } interface CombinedCodeActions { changes: ReadonlyArray; @@ -6313,6 +6314,8 @@ declare namespace ts.server.protocol { * This may be omitted to indicate that the code fix can't be applied in a group. */ fixId?: {}; + /** Should be present if and only if 'fixId' is. */ + fixAllDescription?: string; } /** * Format and format on key response message. diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index f849dc7f664..94dcc50dc28 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4494,6 +4494,7 @@ declare namespace ts { * This may be omitted to indicate that the code fix can't be applied in a group. */ fixId?: {}; + fixAllDescription?: string; } interface CombinedCodeActions { changes: ReadonlyArray; diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc_all.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc_all.ts index 60e10980bb9..d5de68c70ad 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc_all.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc_all.ts @@ -8,6 +8,7 @@ verify.codeFixAll({ fixId: "annotateWithTypeFromJSDoc", + fixAllDescription: "Annotate everything with types from JSDoc", newFileContent: `/** @type {number} */ var x: number; diff --git a/tests/cases/fourslash/codeFixAddMissingInvocationForDecorator_all.ts b/tests/cases/fourslash/codeFixAddMissingInvocationForDecorator_all.ts index f655065e78c..3b0f35b0ac6 100644 --- a/tests/cases/fourslash/codeFixAddMissingInvocationForDecorator_all.ts +++ b/tests/cases/fourslash/codeFixAddMissingInvocationForDecorator_all.ts @@ -11,6 +11,7 @@ verify.codeFixAll({ fixId: "addMissingInvocationForDecorator", + fixAllDescription: "Add '()' to all uncalled decorators", newFileContent: `declare function foo(): (...args: any[]) => void; class C { diff --git a/tests/cases/fourslash/codeFixAddMissingMember_all.ts b/tests/cases/fourslash/codeFixAddMissingMember_all.ts index ae5e957732b..5a2f8606f2d 100644 --- a/tests/cases/fourslash/codeFixAddMissingMember_all.ts +++ b/tests/cases/fourslash/codeFixAddMissingMember_all.ts @@ -10,6 +10,7 @@ verify.codeFixAll({ fixId: "addMissingMember", + fixAllDescription: "Add all missing members", newFileContent: `class C { x: number; diff --git a/tests/cases/fourslash/codeFixAddMissingMember_all_js.ts b/tests/cases/fourslash/codeFixAddMissingMember_all_js.ts index 305b6d87c30..5e5a2895fdc 100644 --- a/tests/cases/fourslash/codeFixAddMissingMember_all_js.ts +++ b/tests/cases/fourslash/codeFixAddMissingMember_all_js.ts @@ -15,6 +15,7 @@ verify.codeFixAll({ fixId: "addMissingMember", + fixAllDescription: "Add all missing members", newFileContent: `class C { y() { diff --git a/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts b/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts index e6314a3a5f0..4b5f7aea0a3 100644 --- a/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts +++ b/tests/cases/fourslash/codeFixAwaitInSyncFunction_all.ts @@ -10,6 +10,7 @@ verify.codeFixAll({ fixId: "fixAwaitInSyncFunction", + fixAllDescription: "Add all missing 'async' modifiers", newFileContent: `async function f() { await Promise.resolve(); diff --git a/tests/cases/fourslash/codeFixCannotFindModule_all.ts b/tests/cases/fourslash/codeFixCannotFindModule_all.ts index bbe4192c256..044d0c5deb0 100644 --- a/tests/cases/fourslash/codeFixCannotFindModule_all.ts +++ b/tests/cases/fourslash/codeFixCannotFindModule_all.ts @@ -22,6 +22,7 @@ goTo.marker(); verify.codeFixAll({ fixId: "fixCannotFindModule", + fixAllDescription: "Install all missing types packages", commands: [ { packageName: "@types/abs", file: "/a.ts", type: "install package" }, { packageName: "@types/zap", file: "/a.ts", type: "install package" }, diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax_all.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax_all.ts index 2c0768c0580..03a51a02f4e 100644 --- a/tests/cases/fourslash/codeFixChangeJSDocSyntax_all.ts +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax_all.ts @@ -5,5 +5,6 @@ verify.codeFixAll({ fixId: "fixJSDocTypes_plain", + fixAllDescription: "Change all jsdoc-style types to TypeScript", newFileContent: "function f(a: number | null, b: string) {}", }) diff --git a/tests/cases/fourslash/codeFixChangeJSDocSyntax_all_nullable.ts b/tests/cases/fourslash/codeFixChangeJSDocSyntax_all_nullable.ts index 5a18fa620f8..2d987128fb1 100644 --- a/tests/cases/fourslash/codeFixChangeJSDocSyntax_all_nullable.ts +++ b/tests/cases/fourslash/codeFixChangeJSDocSyntax_all_nullable.ts @@ -5,5 +5,6 @@ verify.codeFixAll({ fixId: "fixJSDocTypes_nullable", + fixAllDescription: "Change all jsdoc-style types to TypeScript (and add '| undefined' to nullable types)", newFileContent: "function f(a: number | null | undefined, b: string) {}", }) diff --git a/tests/cases/fourslash/codeFixClassExtendAbstractMethod_all.ts b/tests/cases/fourslash/codeFixClassExtendAbstractMethod_all.ts index b158a215ca1..49770ec85ea 100644 --- a/tests/cases/fourslash/codeFixClassExtendAbstractMethod_all.ts +++ b/tests/cases/fourslash/codeFixClassExtendAbstractMethod_all.ts @@ -9,6 +9,7 @@ verify.codeFixAll({ fixId: "fixClassDoesntImplementInheritedAbstractMember", + fixAllDescription: "Implement all inherited abstract classes", newFileContent: `abstract class A { abstract m(): void; diff --git a/tests/cases/fourslash/codeFixClassImplementInterface_all.ts b/tests/cases/fourslash/codeFixClassImplementInterface_all.ts index ae70d6fb422..cdf11eec352 100644 --- a/tests/cases/fourslash/codeFixClassImplementInterface_all.ts +++ b/tests/cases/fourslash/codeFixClassImplementInterface_all.ts @@ -7,6 +7,7 @@ verify.codeFixAll({ fixId: "fixClassIncorrectlyImplementsInterface", + fixAllDescription: "Implement all unimplemented interfaces", newFileContent: `interface I { i(): void; } interface J { j(): void; } diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_1.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_1.ts index 46d50c3c32a..2bf0098ceeb 100644 --- a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_1.ts +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_1.ts @@ -7,38 +7,39 @@ //// class TT { constructor () {} } //// //// class AT extends A { a () {} } -//// +//// //// class Foo {} //// //// class T { -//// +//// //// a: string; -//// +//// //// static b: string; -//// +//// //// private c: string; -//// +//// //// d: number | undefined; -//// +//// //// e: string | number; -//// +//// //// f: 1; -//// +//// //// g: "123" | "456"; -//// +//// //// h: boolean; -//// +//// //// i: TT; -//// +//// //// j: A; -//// +//// //// k: AT; -//// +//// //// l: Foo; //// } verify.codeFixAll({ fixId: 'addMissingPropertyDefiniteAssignmentAssertions', + fixAllDescription: "Add definite assignment assertions to all uninitialized properties", newFileContent: `abstract class A { abstract a (); } class TT { constructor () {} } diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_2.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_2.ts index ccf78aa1124..707b50e5115 100644 --- a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_2.ts +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_2.ts @@ -7,38 +7,39 @@ //// class TT { constructor () {} } //// //// class AT extends A { a () {} } -//// +//// //// class Foo {} //// //// class T { -//// +//// //// a: string; -//// +//// //// static b: string; -//// +//// //// private c: string; -//// +//// //// d: number | undefined; -//// +//// //// e: string | number; -//// +//// //// f: 1; -//// +//// //// g: "123" | "456"; -//// +//// //// h: boolean; -//// +//// //// i: TT; -//// +//// //// j: A; -//// +//// //// k: AT; -//// +//// //// l: Foo; //// } verify.codeFixAll({ fixId: 'addMissingPropertyUndefinedType', + fixAllDescription: "Add undefined type to all uninitialized properties", newFileContent: `abstract class A { abstract a (); } class TT { constructor () {} } diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_3.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_3.ts index 28518d3d16f..5931c6bd977 100644 --- a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_3.ts +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_3.ts @@ -7,38 +7,39 @@ //// class TT { constructor () {} } //// //// class AT extends A { a () {} } -//// +//// //// class Foo {} //// //// class T { -//// +//// //// a: string; -//// +//// //// static b: string; -//// +//// //// private c: string; -//// +//// //// d: number | undefined; -//// +//// //// e: string | number; -//// +//// //// f: 1; -//// +//// //// g: "123" | "456"; -//// +//// //// h: boolean; -//// +//// //// i: TT; -//// +//// //// j: A; -//// +//// //// k: AT; -//// +//// //// l: Foo; //// } verify.codeFixAll({ fixId: 'addMissingPropertyInitializer', + fixAllDescription: "Add initializers to all uninitialized properties", newFileContent: `abstract class A { abstract a (); } class TT { constructor () {} } diff --git a/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess_all.ts b/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess_all.ts index 96f3677fda7..41650e42cac 100644 --- a/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess_all.ts +++ b/tests/cases/fourslash/codeFixClassSuperMustPrecedeThisAccess_all.ts @@ -16,6 +16,7 @@ verify.codeFixAll({ fixId: "classSuperMustPrecedeThisAccess", + fixAllDescription: "Make all 'super()' calls the first statement in their constructor", newFileContent: `class C extends Object { constructor() { super(); diff --git a/tests/cases/fourslash/codeFixConstructorForDerivedNeedSuperCall_all.ts b/tests/cases/fourslash/codeFixConstructorForDerivedNeedSuperCall_all.ts index 3833af62de0..bb576795338 100644 --- a/tests/cases/fourslash/codeFixConstructorForDerivedNeedSuperCall_all.ts +++ b/tests/cases/fourslash/codeFixConstructorForDerivedNeedSuperCall_all.ts @@ -9,6 +9,7 @@ verify.codeFixAll({ fixId: "constructorForDerivedNeedSuperCall", + fixAllDescription: "Add all missing super calls", newFileContent: `class C extends Object { constructor() { super(); diff --git a/tests/cases/fourslash/codeFixCorrectQualifiedNameToIndexedAccessType_all.ts b/tests/cases/fourslash/codeFixCorrectQualifiedNameToIndexedAccessType_all.ts index 334972ea13a..6f769b1f075 100644 --- a/tests/cases/fourslash/codeFixCorrectQualifiedNameToIndexedAccessType_all.ts +++ b/tests/cases/fourslash/codeFixCorrectQualifiedNameToIndexedAccessType_all.ts @@ -8,6 +8,7 @@ verify.codeFixAll({ fixId: "correctQualifiedNameToIndexedAccessType", + fixAllDescription: "Rewrite all as indexed access types", newFileContent: `interface Foo { bar: string; diff --git a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile_all.ts b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile_all.ts index 89f94520374..1a374e5f897 100644 --- a/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile_all.ts +++ b/tests/cases/fourslash/codeFixDisableJsDiagnosticsInFile_all.ts @@ -11,6 +11,7 @@ verify.codeFixAll({ fixId: "disableJsDiagnostics", + fixAllDescription: "Add '@ts-ignore' to all error messages", newFileContent: `let x = ""; // @ts-ignore diff --git a/tests/cases/fourslash/codeFixExtendsInterfaceBecomesImplements_all.ts b/tests/cases/fourslash/codeFixExtendsInterfaceBecomesImplements_all.ts index db039c92890..e1594c72fcb 100644 --- a/tests/cases/fourslash/codeFixExtendsInterfaceBecomesImplements_all.ts +++ b/tests/cases/fourslash/codeFixExtendsInterfaceBecomesImplements_all.ts @@ -6,6 +6,7 @@ verify.codeFixAll({ fixId: "extendsInterfaceBecomesImplements", + fixAllDescription: "Change all extended interfaces to 'implements'", newFileContent: `interface I {} class C implements I {} class D implements I {}`, diff --git a/tests/cases/fourslash/codeFixForgottenThisPropertyAccess_all.ts b/tests/cases/fourslash/codeFixForgottenThisPropertyAccess_all.ts index 75ded0290e6..ab95f6b3355 100644 --- a/tests/cases/fourslash/codeFixForgottenThisPropertyAccess_all.ts +++ b/tests/cases/fourslash/codeFixForgottenThisPropertyAccess_all.ts @@ -10,6 +10,7 @@ verify.codeFixAll({ fixId: "forgottenThisPropertyAccess", + fixAllDescription: "Add 'this.' to all unresolved variables matching a member name", newFileContent: `class C { foo: number; diff --git a/tests/cases/fourslash/codeFixInPropertyAccess_js.ts b/tests/cases/fourslash/codeFixInPropertyAccess_js.ts index 2afde9b5ee1..ef69d889626 100644 --- a/tests/cases/fourslash/codeFixInPropertyAccess_js.ts +++ b/tests/cases/fourslash/codeFixInPropertyAccess_js.ts @@ -18,6 +18,7 @@ verify.codeFixAll({ fixId: "correctQualifiedNameToIndexedAccessType", + fixAllDescription: "Rewrite all as indexed access types", newFileContent: `/** * @typedef Foo diff --git a/tests/cases/fourslash/codeFixInferFromUsage_all.ts b/tests/cases/fourslash/codeFixInferFromUsage_all.ts index 5a6b9d0cbd2..a093b9ab12c 100644 --- a/tests/cases/fourslash/codeFixInferFromUsage_all.ts +++ b/tests/cases/fourslash/codeFixInferFromUsage_all.ts @@ -13,6 +13,7 @@ verify.codeFixAll({ fixId: "inferFromUsage", + fixAllDescription: "Infer all types from usage", newFileContent: `function f(x: number, y: string) { x += 0; diff --git a/tests/cases/fourslash/codeFixSpelling_all.ts b/tests/cases/fourslash/codeFixSpelling_all.ts index 08b73b9ca1b..973f1e1503c 100644 --- a/tests/cases/fourslash/codeFixSpelling_all.ts +++ b/tests/cases/fourslash/codeFixSpelling_all.ts @@ -7,6 +7,7 @@ verify.codeFixAll({ fixId: "fixSpelling", + fixAllDescription: "Fix all detected spelling errors", newFileContent: `function f(s: string) { s.toString(); diff --git a/tests/cases/fourslash/codeFixUnusedIdentifier_all_delete.ts b/tests/cases/fourslash/codeFixUnusedIdentifier_all_delete.ts index f42915249e9..8b7234732e2 100644 --- a/tests/cases/fourslash/codeFixUnusedIdentifier_all_delete.ts +++ b/tests/cases/fourslash/codeFixUnusedIdentifier_all_delete.ts @@ -9,6 +9,7 @@ verify.codeFixAll({ fixId: "unusedIdentifier_delete", + fixAllDescription: "Delete all unused declarations", newFileContent: `function f() { }`, diff --git a/tests/cases/fourslash/codeFixUnusedIdentifier_all_prefix.ts b/tests/cases/fourslash/codeFixUnusedIdentifier_all_prefix.ts index 55475321f94..fb8a2b9a3a4 100644 --- a/tests/cases/fourslash/codeFixUnusedIdentifier_all_prefix.ts +++ b/tests/cases/fourslash/codeFixUnusedIdentifier_all_prefix.ts @@ -9,6 +9,7 @@ verify.codeFixAll({ fixId: "unusedIdentifier_prefix", + fixAllDescription: "Prefix all unused declarations with '_' where possible", newFileContent: `function f(_a, _b) { const x = 0; // Can't be prefixed, ignored diff --git a/tests/cases/fourslash/codeFixUseDefaultImport_all.ts b/tests/cases/fourslash/codeFixUseDefaultImport_all.ts index d3f82d7ed02..0154685d1fe 100644 --- a/tests/cases/fourslash/codeFixUseDefaultImport_all.ts +++ b/tests/cases/fourslash/codeFixUseDefaultImport_all.ts @@ -13,6 +13,7 @@ goTo.file("/b.ts"); verify.codeFixAll({ fixId: "useDefaultImport", + fixAllDescription: "Convert all to default imports", newFileContent: `import a1 from "./a"; import a2 from "./a";`, diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 60ccbf8963a..61899dde030 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -298,7 +298,7 @@ declare namespace FourSlashInterface { docCommentTemplateAt(markerName: string | FourSlashInterface.Marker, expectedOffset: number, expectedText: string): void; noDocCommentTemplateAt(markerName: string | FourSlashInterface.Marker): void; rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void; - codeFixAll(options: { fixId: string, newFileContent: string, commands?: {}[] }): void; + codeFixAll(options: { fixId: string, fixAllDescription: string, newFileContent: string, commands?: {}[] }): void; fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: FormatCodeOptions): void; rangeIs(expectedText: string, includeWhiteSpace?: boolean): void; fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, formattingOptions?: FormatCodeOptions): void;