diff --git a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts index dac8c9d6b..b731accc0 100644 --- a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts @@ -171,6 +171,14 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { ); } + if (fix.fixName === 'fixMissingFunctionDeclaration') { + originalRange = this.checkEndOfFileCodeInsert( + originalRange, + range, + document + ); + } + return TextEdit.replace(originalRange, edit.newText); }) ); @@ -327,23 +335,12 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { TextDocumentEdit.create( VersionedTextDocumentIdentifier.create(document.uri, 0), edit.textChanges.map((edit) => { - let range = mapRangeToOriginal(fragment, convertRange(fragment, edit.span)); - // Some refactorings place the new code at the end of svelte2tsx' render function, - // which is unmapped. In this case, add it to the end of the script tag ourselves. - if (range.start.line < 0 || range.end.line < 0) { - if (isRangeInTag(originalRange, document.scriptInfo)) { - range = Range.create( - document.scriptInfo.endPos, - document.scriptInfo.endPos - ); - } else if (isRangeInTag(originalRange, document.moduleScriptInfo)) { - range = Range.create( - document.moduleScriptInfo.endPos, - document.moduleScriptInfo.endPos - ); - } - } - return TextEdit.replace(range, edit.newText); + const range = mapRangeToOriginal(fragment, convertRange(fragment, edit.span)); + + return TextEdit.replace( + this.checkEndOfFileCodeInsert(range, originalRange, document), + edit.newText + ); }) ) ); @@ -351,6 +348,24 @@ export class CodeActionsProviderImpl implements CodeActionsProvider { return { documentChanges }; } + /** + * Some refactorings place the new code at the end of svelte2tsx' render function, + * which is unmapped. In this case, add it to the end of the script tag ourselves. + */ + private checkEndOfFileCodeInsert(resultRange: Range, targetRange: Range, document: Document) { + if (resultRange.start.line < 0 || resultRange.end.line < 0) { + if (isRangeInTag(targetRange, document.scriptInfo)) { + resultRange = Range.create(document.scriptInfo.endPos, document.scriptInfo.endPos); + } else if (isRangeInTag(targetRange, document.moduleScriptInfo)) { + resultRange = Range.create( + document.moduleScriptInfo.endPos, + document.moduleScriptInfo.endPos + ); + } + } + return resultRange; + } + private getLSAndTSDoc(document: Document) { return this.lsAndTsDocResolver.getLSAndTSDoc(document); } diff --git a/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts b/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts index 2630bc70f..13f701011 100644 --- a/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts +++ b/packages/language-server/test/plugins/typescript/features/CodeActionsProvider.test.ts @@ -95,6 +95,63 @@ describe('CodeActionsProvider', () => { ]); }); + it('provides quickfix for missing function', async () => { + const { provider, document } = setup('codeactions.svelte'); + + const codeActions = await provider.getCodeActions( + document, + Range.create(Position.create(9, 0), Position.create(9, 3)), + { + diagnostics: [ + { + code: 2304, + message: "Cannot find name 'abc'.", + range: Range.create(Position.create(9, 0), Position.create(9, 3)), + source: 'ts' + } + ], + only: [CodeActionKind.QuickFix] + } + ); + + (codeActions[0]?.edit?.documentChanges?.[0])?.edits.forEach( + (edit) => (edit.newText = harmonizeNewLines(edit.newText)) + ); + + assert.deepStrictEqual(codeActions, [ + { + edit: { + documentChanges: [ + { + edits: [ + { + newText: + "\n\nfunction abc() {\nthrow new Error('Function not implemented.');\n}\n", + range: { + start: { + character: 0, + line: 10 + }, + end: { + character: 0, + line: 10 + } + } + } + ], + textDocument: { + uri: getUri('codeactions.svelte'), + version: 0 + } + } + ] + }, + kind: CodeActionKind.QuickFix, + title: "Add missing function declaration 'abc'" + } + ]); + }); + it('organizes imports', async () => { const { provider, document } = setup('codeactions.svelte'); @@ -428,11 +485,11 @@ describe('CodeActionsProvider', () => { range: { start: { character: 0, - line: 9 + line: 10 }, end: { character: 0, - line: 9 + line: 10 } } } diff --git a/packages/language-server/test/plugins/typescript/testfiles/codeactions.svelte b/packages/language-server/test/plugins/typescript/testfiles/codeactions.svelte index c7ff8b71e..f38f7368b 100644 --- a/packages/language-server/test/plugins/typescript/testfiles/codeactions.svelte +++ b/packages/language-server/test/plugins/typescript/testfiles/codeactions.svelte @@ -7,4 +7,5 @@ import {D} from 'd'; let a = true; A;C; let b = Math.random() > 0.5 ? true : false; +abc();