From 36e67a4bd5b411ad68a3506f8a188a56e308af52 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Thu, 18 Jan 2024 06:54:25 -0800 Subject: [PATCH 01/18] Testing basic changes --- src/harness/client.ts | 14 ++ src/harness/fourslashImpl.ts | 13 ++ src/harness/fourslashInterfaceImpl.ts | 12 ++ src/server/project.ts | 123 +++++++++++++++++ src/server/protocol.ts | 24 ++++ src/server/session.ts | 9 ++ .../_namespaces/ts.postPasteImportFixes.ts | 1 + src/services/_namespaces/ts.ts | 2 + src/services/codefixes/importFixes.ts | 8 +- src/services/postPasteImportFix.ts | 130 ++++++++++++++++++ src/services/services.ts | 17 +++ src/services/types.ts | 16 ++- tests/cases/fourslash/fourslash.ts | 14 ++ .../fourslash/server/postPasteImportFix1.ts | 28 ++++ .../fourslash/server/postPasteImportFix2.ts | 38 +++++ .../fourslash/server/postPasteImportFix3.ts | 31 +++++ 16 files changed, 475 insertions(+), 5 deletions(-) create mode 100644 src/services/_namespaces/ts.postPasteImportFixes.ts create mode 100644 src/services/postPasteImportFix.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFix1.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFix2.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFix3.ts diff --git a/src/harness/client.ts b/src/harness/client.ts index 619fece8cae62..3f6d72f88f2f6 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -13,6 +13,7 @@ import { computeLineAndCharacterOfPosition, computeLineStarts, computePositionOfLineAndCharacter, + CopyRange, createQueue, createTextSpanFromBounds, Debug, @@ -1009,6 +1010,19 @@ export class SessionClient implements LanguageService { return getSupportedCodeFixes(); } + getPostPasteImportFixes(targetFile: string, pastes: Array<{text: string; range: TextRange}>, _preferences: UserPreferences, _formatOptions: FormatCodeSettings, originalFile?: string, copyRange?: CopyRange): FileTextChanges[]{ + const t = this.createFileRangeRequestArgs(targetFile, pastes[0].range.pos, pastes[0].range.end); + const args = this.createFileLocationOrRangeRequestArgs(pastes[0].range, targetFile) as protocol.GetPostPasteImportFixesRequestArgs; //needs to be fixed + args.targetFile = targetFile; + args.pastes = [{text: pastes[0].text, range: t}]; + args.originalFile = originalFile; + args.copyRange = copyRange; + + const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); + const response = this.processResponse(request); + return []; + } + getProgram(): Program { throw new Error("Program objects are not serializable through the server protocol."); } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 5763b24c6bde6..99109ad800025 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -3554,6 +3554,19 @@ export class TestState { assert.deepEqual(actualModuleSpecifiers, moduleSpecifiers); } + public getPostPasteImportFixes( + targetFile: string, + pastes: Array<{text: string; range: ts.TextRange}>,//{ pos, end }: ts.TextRange + preferences: ts.UserPreferences, + originalFile?: string, + copyRange?: ts.CopyRange + ){ + const range = this.getSelection(); + //const range: ts.TextRange = {pos: pastes[0].range.pos, end: pastes[0].range.end}; + const t = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, pastes, preferences, this.formatCodeSettings, originalFile, copyRange); + return "hello"; + } + public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined, options?: ts.DocCommentTemplateOptions) { const name = "verifyDocCommentTemplate"; const actual = this.languageService.getDocCommentTemplateAtPosition(this.activeFile.fileName, this.currentCaretPosition, options || { generateReturnInDocTemplate: true }, this.formatCodeSettings)!; diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 52e028c5070bb..d1fdea4aef33e 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -620,6 +620,10 @@ export class Verify extends VerifyNegatable { public organizeImports(newContent: string, mode?: ts.OrganizeImportsMode, preferences?: ts.UserPreferences): void { this.state.verifyOrganizeImports(newContent, mode, preferences); } + + public postPasteImportFix(options: verifyPostPasteImportFix): void { + this.state.getPostPasteImportFixes(options.targetFile, options.pastes, options.preferences, options.originalFile, options.copyRange); + } } export class Edit { @@ -1872,6 +1876,14 @@ export interface VerifyCodeFixAllOptions { preferences?: ts.UserPreferences; } +export interface verifyPostPasteImportFix { + targetFile: string; + pastes: Array<{text: string; range: ts.TextRange}>; + preferences: ts.UserPreferences; + originalFile?: string; + copyRange?: ts.CopyRange +} + export interface VerifyRefactorOptions { name: string; actionName: string; diff --git a/src/server/project.ts b/src/server/project.ts index fbac2fb111c35..57ecf77f24db5 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1,3 +1,4 @@ +import { getExportInfos, getImportFixes, getSymbolNamesToImport, shouldUseRequire } from "../services/codefixes/importFixes"; import * as ts from "./_namespaces/ts"; import { addRange, @@ -2212,6 +2213,128 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return this.noDtsResolutionProject; } + // export anotherGetFixes(updatedFile: ts.SourceFile, originalProgram: ts.Program, node: ts.Identifier, languageServiceHost: this, cancellationToken: ts.CancellationToken, preferences: ts.UserPreferences) { + // const imports = flatMap(getSymbolNamesToImport(updatedFile, originalProgram.getTypeChecker(), node, originalProgram.getCompilerOptions()), symbolName => { + // // "default" is a keyword and not a legal identifier for the import, but appears as an identifier. + // if (symbolName === ts.InternalSymbolName.Default) { + // return undefined; + // } + // const isValidTypeOnlyUseSite = ts.isValidTypeOnlyAliasUseSite(node); + // const useRequire = shouldUseRequire(updatedFile, originalProgram); + // const exportInfo = getExportInfos(symbolName, ts.isJSXTagName(node), ts.getMeaningFromLocation(node), cancellationToken, updatedFile, originalProgram, true, languageServiceHost, preferences); + // return arrayFrom( + // ts.flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(updatedFile), isValidTypeOnlyUseSite, useRequire, originalProgram, updatedFile, languageServiceHost, preferences).fixes), + // fix => ({ fix, symbolName, errorIdentifierText: node.text, isJsxNamespaceFix: symbolName !== node.text }), + // ); + // } + // } + + /** @internal */ + updatedTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: ts.Program | undefined} { + const originalProgram = this.program; + this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length-1, pastedText); + this.updateGraph(); + const updatedFile = this.program?.getSourceFile(rootFile); + const updatedProgram = this.program; + return { updatedFile, updatedProgram, originalProgram }; + } + /** @internal */ + getFakeSourceFile(rootFile: string, pastedText: string, _targetFileName: string, targetFileText: string): [] | undefined { + + /** + * cscriptInfo.editContent() + * project.updateGraph gives the new SF + * after scriptInfo.editContent("") the new SF is not updated + */ + //const t = this.getScriptInfo(rootFile); + // const scriptInfo = this.projectService.getScriptInfoForPath(this.toPath(rootFile)); + this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length, pastedText); + this.updateGraph(); + const updatedFile = this.program?.getSourceFile(rootFile); + const updatedProgram = this.program; + + const originalProgram = this.program; + const cancellationToken = this.cancellationToken; + const languageServiceHost = this; + const preferences = this.projectService.getPreferences(toNormalizedPath(rootFile)); + let allImports:[] | undefined; + + if (updatedFile && updatedProgram && originalProgram) { + ts.forEachChild(updatedFile, function cb(node) { + if (ts.isIdentifier(node)) { + if (!updatedProgram.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ true) && + !originalProgram?.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ false)) { + //generate imports + const imports = flatMap(getSymbolNamesToImport(updatedFile, originalProgram.getTypeChecker(), node, originalProgram.getCompilerOptions()), symbolName => { + // "default" is a keyword and not a legal identifier for the import, but appears as an identifier. + if (symbolName === ts.InternalSymbolName.Default) { + return undefined; + } + const isValidTypeOnlyUseSite = ts.isValidTypeOnlyAliasUseSite(node); + const useRequire = shouldUseRequire(updatedFile, originalProgram); + const exportInfo = getExportInfos(symbolName, ts.isJSXTagName(node), ts.getMeaningFromLocation(node), cancellationToken, updatedFile, originalProgram, true, languageServiceHost, preferences); + const t = arrayFrom( + ts.flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(updatedFile), isValidTypeOnlyUseSite, useRequire, originalProgram, updatedFile, languageServiceHost, preferences).fixes), + fix => ({ fix, symbolName, errorIdentifierText: node.text, isJsxNamespaceFix: symbolName !== node.text }), + ); + }); + } + } + else { + node.forEachChild(cb); + } + }); + } + + // const program: Program = ts.createProgram([rootFile], this.getCompilerOptions(), { + // getSourceFile:() => ts.createSourceFile("fake source file", pastedText, { languageVersion: ts.ScriptTarget.ES2015, jsDocParsingMode: JSDocParsingMode.ParseNone }, /*setParentNodes*/ false), + // getDefaultLibFileName: () => ts.getDefaultLibFilePath(this.getCompilerOptions()), + // writeFile: noop, + // getCurrentDirectory: () => this.getCurrentDirectory(), + // getCanonicalFileName: () => "fake source file", + // useCaseSensitiveFileNames: () => true, + // getNewLine: () => "\n", + // fileExists(){return true}, + // readFile() { + // return pastedText; + // } + // }); + // const fakeSourceFile = program.getSourceFile("fake source file"); + // const originalProgram = this.program; + // const cancellationToken = this.cancellationToken; + // const languageServiceHost = this; + // const preferences = this.projectService.getPreferences(toNormalizedPath(rootFile)); + // let imports; + + // if (fakeSourceFile && originalProgram) { + // ts.forEachChild(fakeSourceFile, function cb(node) { + // if (ts.isIdentifier(node)) { + // if (!program.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ true) && + // !originalProgram?.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ false)) { + // //generate imports + // imports = flatMap(getSymbolNamesToImport(fakeSourceFile, originalProgram.getTypeChecker(), node, originalProgram.getCompilerOptions()), symbolName => { + // // "default" is a keyword and not a legal identifier for the import, but appears as an identifier. + // if (symbolName === ts.InternalSymbolName.Default) { + // return undefined; + // } + // const isValidTypeOnlyUseSite = ts.isValidTypeOnlyAliasUseSite(node); + // const useRequire = shouldUseRequire(fakeSourceFile, originalProgram); + // const exportInfo = getExportInfos(symbolName, ts.isJSXTagName(node), ts.getMeaningFromLocation(node), cancellationToken, fakeSourceFile, originalProgram, true, languageServiceHost, preferences); + // return arrayFrom( + // ts.flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(fakeSourceFile), isValidTypeOnlyUseSite, useRequire, program, fakeSourceFile, languageServiceHost, preferences).fixes), + // fix => ({ fix, symbolName, errorIdentifierText: node.text, isJsxNamespaceFix: symbolName !== node.text }), + // ); + // }); + // } + // } + // else { + // node.forEachChild(cb); + // } + // }); + // } + return allImports; + } + /** @internal */ private getCompilerOptionsForNoDtsResolutionProject() { return { diff --git a/src/server/protocol.ts b/src/server/protocol.ts index ae6c5bc055143..fe99eb2440307 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -144,6 +144,7 @@ export const enum CommandTypes { GetApplicableRefactors = "getApplicableRefactors", GetEditsForRefactor = "getEditsForRefactor", GetMoveToRefactoringFileSuggestions = "getMoveToRefactoringFileSuggestions", + GetPostPasteImportFixes = "getPostPasteImportFixes", /** @internal */ GetEditsForRefactorFull = "getEditsForRefactor-full", @@ -630,6 +631,29 @@ export interface GetMoveToRefactoringFileSuggestions extends Response { }; } +/** + * Request refactorings at a given position post pasting text from some other location. + */ + +export interface GetPostPasteImportFixesRequest extends Request { + command: CommandTypes.GetPostPasteImportFixes; + arguments: GetPostPasteImportFixesRequestArgs; +} +export type DocumentRange = FileRangeRequestArgs; +export type CopyRange = { + start: Location; + end: Location; +} +export type GetPostPasteImportFixesRequestArgs = FileLocationOrRangeRequestArgs & { + targetFile: string, + pastes: Array<{text: string; range: DocumentRange}>, + originalFile?: string, + copyRange?: CopyRange +} +export interface GetPostPasteImportFixesResponse extends Response { + filename: string; +} + /** * A set of one or more available refactoring actions, grouped under a parent refactoring. */ diff --git a/src/server/session.ts b/src/server/session.ts index 116ff92c5d9f9..bfb054f1c5a7c 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2796,6 +2796,12 @@ export class Session implements EventSender { return project.getLanguageService().getMoveToRefactoringFileSuggestions(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file)); } + private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs) { + const { file, project } = this.getFileAndProject(args); + const textRange = this.getRange(args.pastes[0].range, project.getScriptInfoForNormalizedPath(file)!); + return project.getLanguageService().getPostPasteImportFixes(args.targetFile, [{text: args.pastes[0].text, range: textRange}], this.getPreferences(file), this.getFormatOptions(file), args.originalFile, args.copyRange); + } + private organizeImports(args: protocol.OrganizeImportsRequestArgs, simplifiedResult: boolean): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { Debug.assert(args.scope.type === "file"); const { file, project } = this.getFileAndProject(args.scope.args); @@ -3521,6 +3527,9 @@ export class Session implements EventSender { [protocol.CommandTypes.GetMoveToRefactoringFileSuggestions]: (request: protocol.GetMoveToRefactoringFileSuggestionsRequest) => { return this.requiredResponse(this.getMoveToRefactoringFileSuggestions(request.arguments)); }, + [protocol.CommandTypes.GetPostPasteImportFixes]: (request: protocol.GetPostPasteImportFixesRequest) => { + return this.requiredResponse(this.getPostPasteImportFixes(request.arguments)); + }, [protocol.CommandTypes.GetEditsForRefactorFull]: (request: protocol.GetEditsForRefactorRequest) => { return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ false)); }, diff --git a/src/services/_namespaces/ts.postPasteImportFixes.ts b/src/services/_namespaces/ts.postPasteImportFixes.ts new file mode 100644 index 0000000000000..c46fc22994e95 --- /dev/null +++ b/src/services/_namespaces/ts.postPasteImportFixes.ts @@ -0,0 +1 @@ +export * from "../postPasteImportFix"; \ No newline at end of file diff --git a/src/services/_namespaces/ts.ts b/src/services/_namespaces/ts.ts index e30ea818a04b5..a0fb6bf9ca8ff 100644 --- a/src/services/_namespaces/ts.ts +++ b/src/services/_namespaces/ts.ts @@ -56,3 +56,5 @@ import * as textChanges from "./ts.textChanges"; export { textChanges }; import * as formatting from "./ts.formatting"; export { formatting }; +import * as postPasteImportFixes from "./ts.postPasteImportFixes"; +export { postPasteImportFixes }; diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 97c5bca540b54..295fc31b62c5d 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -626,7 +626,7 @@ function getSingleExportInfoForSymbol(symbol: Symbol, symbolName: string, module } } -function getImportFixes( +export function getImportFixes( exportInfos: readonly SymbolExportInfo[], usagePosition: number | undefined, isValidTypeOnlyUseSite: boolean, @@ -833,7 +833,7 @@ function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile }; } -function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean { +export function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean { // 1. TypeScript files don't use require variable declarations if (!isSourceFileJS(sourceFile)) { return false; @@ -1198,7 +1198,7 @@ function getTypeOnlyPromotionFix(sourceFile: SourceFile, symbolToken: Identifier return { kind: ImportFixKind.PromoteTypeOnly, typeOnlyAliasDeclaration }; } -function getSymbolNamesToImport(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier, compilerOptions: CompilerOptions): string[] { +export function getSymbolNamesToImport(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier, compilerOptions: CompilerOptions): string[] { const parent = symbolToken.parent; if ((isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken && jsxModeNeedsExplicitImport(compilerOptions.jsx)) { const jsxNamespace = checker.getJsxNamespace(sourceFile); @@ -1217,7 +1217,7 @@ function needsJsxNamespaceFix(jsxNamespace: string, symbolToken: Identifier, che } // Returns a map from an exported symbol's ID to a list of every way it's (re-)exported. -function getExportInfos( +export function getExportInfos( symbolName: string, isJsxTagName: boolean, currentTokenMeaning: SemanticMeaning, diff --git a/src/services/postPasteImportFix.ts b/src/services/postPasteImportFix.ts new file mode 100644 index 0000000000000..0484322259dcb --- /dev/null +++ b/src/services/postPasteImportFix.ts @@ -0,0 +1,130 @@ +import { addRange, append } from "../compiler/core"; +import { SourceFile, Statement, UserPreferences, TypeChecker, AnyImportOrRequireStatement, Identifier, ModifierFlags, Program, TextRange } from "../compiler/types"; +import { hasSyntacticModifier, skipAlias } from "../compiler/utilities"; +import { codefix, factory, fileShouldUseJavaScriptRequire, formatting, getLineInfo, getQuotePreference, insertImports, nodeSeenTracker, Symbol, textChanges } from "./_namespaces/ts"; +import { addExportToChanges, filterImport, forEachImportInStatement, getTopLevelDeclarationStatement, getUsageInfo, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./refactors/moveToFile"; +import { CopyRange, FileTextChanges, LanguageServiceHost } from "./types"; + +/** @internal */ +export function postPastImportFixProvider( + targetFile: SourceFile, + host: LanguageServiceHost, + pastes: Array<{text: string; range: TextRange}>, + preferences: UserPreferences, + formatContext: formatting.FormatContext, + originalFile?: SourceFile, + copyLocation?: CopyRange): FileTextChanges[] { + + /** + * When the source file exists + * 1.Need to turn pasted text, in pastes.text into statements + * 2.use getUsageInfo() to the symbols that need to be imported + * 3.use the if and the third part of getTargetFileImportsAndAddExportInOldFile + * */ + const { updatedFile, updatedProgram, originalProgram } = host.updatedTargetFile(targetFile.fileName, targetFile.text, pastes[0].text); + let statements: Statement[] = []; + + if (originalFile && originalProgram && updatedFile && updatedProgram) { + //addRange(statements, updatedFile?.statements, updatedFile?.statements.length - (targetFileStatements ? targetFileStatements.length : 0) - 1); + //addRange(statements, originalFile?.statements, 2); + //const start = originalFile.statements[0].getStart(originalFile);//addRange(statements, originalFile.statements, updatedFile.statements[updatedFile.statements.length - targetFileStatements.length].getStart(originalFile)) + + //addRange(statements, updatedFile.statements, a.getStart(originalFile), b.getStart(originalFile)); + // const a = updatedFile.statements[updatedFile.getLineAndCharacterOfPosition(pastes[0].range.pos).line] //21 + // const b = updatedFile.statements[updatedFile.getLineAndCharacterOfPosition(pastes[0].range.end).line] //pastes[0].range.end + pastes[0].range.length - 1 + addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation?.end.line); + const usage = getUsageInfo(originalFile, statements, originalProgram.getTypeChecker()); + const importAdder = codefix.createImportAdder(updatedFile, updatedProgram, preferences, host); + + return textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => getImports(originalFile, updatedFile, statements, updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, + usage.targetFileImportsFromOldFile, changeTracker, preferences, host, updatedProgram.getTypeChecker())); + } + else { + return []; + } + + + //const unknownSymbols = host.getFakeSourceFile(targetFile,pastes[0].text,targetFile, targetFileText); +} + +function getImports( + originalFile: SourceFile, + targetFile: SourceFile, + statements: Statement[], + program: Program, + importAdder: codefix.ImportAdder, + importsToCopy: Map, + targetFileImportsFromOldFile: Set, + changes: textChanges.ChangeTracker, + preferences: UserPreferences, + host: LanguageServiceHost, + checker: TypeChecker) { + + const imports = getTargetFileImportsForKnownOriginalFile(originalFile, targetFile, program, importAdder, importsToCopy, targetFileImportsFromOldFile, changes, preferences, host, checker); + if (imports.length > 0) { + insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); + } + importAdder.writeFixes(changes, getQuotePreference(originalFile, preferences)); + changes.insertNodesAtEndOfFile(targetFile, statements, true); //NEEDS TO BE FIXED!!!!!!!!!!!! +} + +function getTargetFileImportsForKnownOriginalFile( + originalFile: SourceFile, + targetFile: SourceFile, + program: Program, + importAdder: codefix.ImportAdder, + importsToCopy: Map, + targetFileImportsFromOldFile: Set, + changes: textChanges.ChangeTracker, + preferences: UserPreferences, + host: LanguageServiceHost, + checker: TypeChecker) { + const copiedOldImports: AnyImportOrRequireStatement[] = []; + importsToCopy.forEach((isValidTypeOnlyUseSite, symbol) => { + try { + importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker), isValidTypeOnlyUseSite); + } + catch { + for (const oldStatement of originalFile.statements) { //might be changed to just statements, meaning that the updated statements in the target file + forEachImportInStatement(oldStatement, i => { + append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + }); + } + } + }); + + const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(targetFile.fileName, program, host, !!originalFile.commonJsModuleIndicator); + const quotePreference = getQuotePreference(targetFile, preferences); + // Also, import things used from the old file, and insert 'export' modifiers as necessary in the old file. + let oldFileDefault: Identifier | undefined; + const oldFileNamedImports: string[] = []; + const markSeenTop = nodeSeenTracker(); // Needed because multiple declarations may appear in `const x = 0, y = 1;`. + targetFileImportsFromOldFile.forEach(symbol => { + if (!symbol.declarations) { + return; + } + for (const decl of symbol.declarations) { + if (!isTopLevelDeclaration(decl)) continue; + const name = nameOfTopLevelDeclaration(decl); + if (!name) continue; + + const top = getTopLevelDeclarationStatement(decl); + if (markSeenTop(top)) { + addExportToChanges(originalFile, top, name, changes, useEsModuleSyntax); + } + if (importAdder && checker.isUnknownSymbol(symbol)) { + importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker)); + } + else { + if (hasSyntacticModifier(decl, ModifierFlags.Default)) { + oldFileDefault = name; + } + else { + oldFileNamedImports.push(name.text); + } + } + } + }); + + return append(copiedOldImports, makeImportOrRequire(targetFile, oldFileDefault, oldFileNamedImports, originalFile.fileName, program, host, useEsModuleSyntax, quotePreference)) +} diff --git a/src/services/services.ts b/src/services/services.ts index 812eafd2c940e..e6a90ad61c966 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -319,6 +319,8 @@ import { updateSourceFile, UserPreferences, VariableDeclaration, + postPasteImportFixes, + CopyRange, } from "./_namespaces/ts"; import * as NavigateTo from "./_namespaces/ts.NavigateTo"; import * as NavigationBar from "./_namespaces/ts.NavigationBar"; @@ -2089,6 +2091,20 @@ export function createLanguageService( }; } + function getPostPasteImportFixes ( + targetFile: string, + pastes: Array<{text: string; range: TextRange}>, + preferences: UserPreferences, + formatOptions: FormatCodeSettings, + originalFile?: string, + copyLocation?: CopyRange + ): FileTextChanges[]{ + synchronizeHostData(); + const originalSourceFile = originalFile ? getValidSourceFile(originalFile) : undefined; + const edits = postPasteImportFixes.postPastImportFixProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host), originalSourceFile, copyLocation); + return edits; + } + function getNodeForQuickInfo(node: Node): Node { if (isNewExpression(node.parent) && node.pos === node.parent.pos) { return node.parent.expression; @@ -3155,6 +3171,7 @@ export function createLanguageService( uncommentSelection, provideInlayHints, getSupportedCodeFixes, + getPostPasteImportFixes }; switch (languageServiceMode) { diff --git a/src/services/types.ts b/src/services/types.ts index 9bb560af02ac9..b40afb2f71d6e 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -431,7 +431,9 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; /** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; - + /** @internal */ getFakeSourceFile(rootFile: string, pastedText: string, targetFileName: string, targetFileText: string) : [] | undefined; + /** @internal */ updatedTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: Program | undefined}; +//needs to be changed to optional jsDocParsingMode?: JSDocParsingMode | undefined; } @@ -684,6 +686,12 @@ export interface LanguageService { getSupportedCodeFixes(fileName?: string): readonly string[]; dispose(): void; + getPostPasteImportFixes (targetFile: string, pastes: Array<{text: string; range: TextRange}>, preferences: UserPreferences, formatOptions: FormatCodeSettings, originalFile: string | undefined, copyLocation: CopyRange | undefined): FileTextChanges[]; +} + +export interface CopyRange { + start: { line: number, offset: number }; + end: { line: number, offset: number } } export interface JsxClosingTagInfo { @@ -706,6 +714,12 @@ export const enum OrganizeImportsMode { RemoveUnused = "RemoveUnused", } +export interface postPasteImportFix { + targetFile: string, + targetFileText: string, + pastes: Array<{text: string; range: TextSpan}> +} + export interface OrganizeImportsArgs extends CombinedCodeFixScope { /** @deprecated Use `mode` instead */ skipDestructiveCodeActions?: boolean; diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index b61f947e488b1..6722b3ef4b31e 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -212,6 +212,14 @@ declare namespace FourSlashInterface { start: number; end: number; } + interface Location { + line: number; + offset: number; + } + interface CopyRange { + start: Location; + end: Location; + } class test_ { markers(): Marker[]; markerNames(): string[]; @@ -444,6 +452,12 @@ declare namespace FourSlashInterface { toggleMultilineComment(newFileContent: string): void; commentSelection(newFileContent: string): void; uncommentSelection(newFileContent: string): void; + postPasteImportFix(options: { + targetFile: string, + pastes: Array<{text: string; range: {pos: number, end: number}}> + originalFile?: string, + copyRange?: CopyRange, + }): void; } class edit { caretPosition(): Marker; diff --git a/tests/cases/fourslash/server/postPasteImportFix1.ts b/tests/cases/fourslash/server/postPasteImportFix1.ts new file mode 100644 index 0000000000000..2918b3d89a660 --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFix1.ts @@ -0,0 +1,28 @@ +/// + +// @Filename: file1.ts +//// export interface Test1 {} +//// export interface Test2 {} +//// export interface Test3 {} +//// export interface Test4 {} + +// @Filename: file2.ts +//// /*a*/const a = 10;/*b*/ + +// @Filename: tsconfig.json +////{ "files": ["file1.ts", "file2.ts"] } + +goTo.select("a", "b"); +verify.postPasteImportFix({ + targetFile: "file2.ts", + pastes: [{ + text: `const a = 10; + interface Testing { + test1: Test1; + test2: Test2; + test3: Test3; + test4: Test4; + }`, + range: { pos: 0, end: 54 }, + }], +}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix2.ts b/tests/cases/fourslash/server/postPasteImportFix2.ts new file mode 100644 index 0000000000000..e5385136e07de --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFix2.ts @@ -0,0 +1,38 @@ +/// + +// @Filename: file1.ts +//// export interface Test1 {} +//// export interface Test2 {} +//// export interface Test3 {} +//// export interface Test4 {} + +// @Filename: file2.ts +//// import { Test1, Test2, Test3, Test4 } from './file1'; +//// interface Testing { +//// test1: Test1; +//// test2: Test2; +//// test3: Test3; +//// test4: Test4; +//// } + +// @Filename: file3.ts +//// /*a*/const a = 10;/*b*/ + +// @Filename: tsconfig.json +////{ "files": ["file1.ts", "file2.ts", "file3.ts"] } + +goTo.select("a", "b"); +verify.postPasteImportFix({ + targetFile: "file3.ts", + pastes: [{ + text: `const a = 10; + interface Testing { + test1: Test1; + test2: Test2; + test3: Test3; + test4: Test4; + }`, + range: { pos: 13, end: 54 }, + }], + originalFile: "file2.ts", +}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix3.ts b/tests/cases/fourslash/server/postPasteImportFix3.ts new file mode 100644 index 0000000000000..2472277f67f65 --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFix3.ts @@ -0,0 +1,31 @@ +/// + +// @Filename: file1.ts +////export const b = 2; + +// @Filename: file2.ts +////import { b } from './other'; +////const a = 1; +////const c = a + b; +////const t = 9; + +// @Filename: file3.ts +//// /*a*/export const tt = 2;/*b*/ +//// function f(); + +// @Filename: tsconfig.json +////{ "files": ["file1.ts", "file2.ts", "file3.ts"] } + +goTo.select("a", "b"); +verify.postPasteImportFix({ + targetFile: "file3.ts", + pastes: [{ + text: `export const tt = 2; + const c = a + b; + const t = 9; + function f();`, + range: { pos: 20, end: 29 }, + }], + originalFile: "file2.ts", + copyRange: { start: { line : 3, offset: 0}, end : { line: 4, offset: 21}}, +}); \ No newline at end of file From 5d931f86c759b327255c478f95eb54d5100d3cb7 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Thu, 25 Jan 2024 16:42:43 -0800 Subject: [PATCH 02/18] Basix structure working --- src/harness/client.ts | 21 +- src/harness/fourslashImpl.ts | 12 +- src/harness/fourslashInterfaceImpl.ts | 12 +- src/server/project.ts | 184 +++++++++++------- src/server/protocol.ts | 5 +- src/server/session.ts | 22 ++- src/services/codefixes/importFixes.ts | 10 +- src/services/postPasteImportFix.ts | 137 +++++++++++-- src/services/services.ts | 3 +- src/services/types.ts | 18 +- tests/cases/fourslash/fourslash.ts | 1 + .../fourslash/server/postPasteImportFix1.ts | 21 +- .../fourslash/server/postPasteImportFix3.ts | 34 +++- 13 files changed, 352 insertions(+), 128 deletions(-) diff --git a/src/harness/client.ts b/src/harness/client.ts index 3f6d72f88f2f6..c89433352209d 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -51,6 +51,7 @@ import { OrganizeImportsArgs, OutliningSpan, PatternMatchKind, + PostPasteImportFixes, Program, QuickInfo, RefactorEditInfo, @@ -1010,7 +1011,7 @@ export class SessionClient implements LanguageService { return getSupportedCodeFixes(); } - getPostPasteImportFixes(targetFile: string, pastes: Array<{text: string; range: TextRange}>, _preferences: UserPreferences, _formatOptions: FormatCodeSettings, originalFile?: string, copyRange?: CopyRange): FileTextChanges[]{ + getPostPasteImportFixes(targetFile: string, pastes: Array<{text: string; range: TextRange}>, _preferences: UserPreferences, _formatOptions: FormatCodeSettings, originalFile?: string, copyRange?: CopyRange): PostPasteImportFixes[]{ const t = this.createFileRangeRequestArgs(targetFile, pastes[0].range.pos, pastes[0].range.end); const args = this.createFileLocationOrRangeRequestArgs(pastes[0].range, targetFile) as protocol.GetPostPasteImportFixesRequestArgs; //needs to be fixed args.targetFile = targetFile; @@ -1020,7 +1021,23 @@ export class SessionClient implements LanguageService { const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); const response = this.processResponse(request); - return []; + if (!response.body) { + return []; + } + + // return response.body!.map(({ fixName, description, changes, commands, fixId, fixAllDescription }) => // TODO: GH#18217 + // ({ fixName, description, changes: this.convertChanges(changes, file), commands: commands as CodeActionCommand[], fixId, fixAllDescription })); + + //const q = response.body.map(({changes}) => ({this.convertChanges(changes, targetFile)})); + //const r: FileTextChanges[] = response.body.map(item =>({changes: this.convertCodeEditsToTextChanges(item.edits)})); + /////////const q = response.body.map(item =>this.convertCodeEditsToTextChanges(item.edits)); + const e = response.body.map(item => ({changes: this.convertCodeEditsToTextChanges(item.edits)})) + // let allEdits: FileTextChanges[] = []; + // for (const edits of response.body) { + // allEdits = this.convertCodeEditsToTextChanges(edits); + // } + // const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body); + return e; } getProgram(): Program { diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 99109ad800025..05e9b675a0a63 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -3554,17 +3554,11 @@ export class TestState { assert.deepEqual(actualModuleSpecifiers, moduleSpecifiers); } - public getPostPasteImportFixes( - targetFile: string, - pastes: Array<{text: string; range: ts.TextRange}>,//{ pos, end }: ts.TextRange - preferences: ts.UserPreferences, - originalFile?: string, - copyRange?: ts.CopyRange - ){ + public getPostPasteImportFixes(options: FourSlashInterface.PostPasteImportFixOptions): void{ const range = this.getSelection(); //const range: ts.TextRange = {pos: pastes[0].range.pos, end: pastes[0].range.end}; - const t = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, pastes, preferences, this.formatCodeSettings, originalFile, copyRange); - return "hello"; + const editInfo = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, options.pastes, options.preferences, this.formatCodeSettings, options.originalFile, options.copyRange); + this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo[0].changes); } public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined, options?: ts.DocCommentTemplateOptions) { diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index d1fdea4aef33e..a3d92dd98f6d5 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -621,8 +621,8 @@ export class Verify extends VerifyNegatable { this.state.verifyOrganizeImports(newContent, mode, preferences); } - public postPasteImportFix(options: verifyPostPasteImportFix): void { - this.state.getPostPasteImportFixes(options.targetFile, options.pastes, options.preferences, options.originalFile, options.copyRange); + public postPasteImportFix(options: PostPasteImportFixOptions): void { + this.state.getPostPasteImportFixes(options); } } @@ -1924,6 +1924,14 @@ export interface MoveToFileOptions { readonly preferences?: ts.UserPreferences; } +export interface PostPasteImportFixOptions { + readonly newFileContents: { readonly [fileName: string]: string; }; + readonly pastes: Array<{text: string; range: ts.TextRange}>,//{ pos, end }: ts.TextRange + readonly preferences: ts.UserPreferences, + readonly originalFile?: string, + readonly copyRange?: ts.CopyRange +} + export type RenameLocationsOptions = readonly RenameLocationOptions[] | { readonly findInStrings?: boolean; readonly findInComments?: boolean; diff --git a/src/server/project.ts b/src/server/project.ts index 57ecf77f24db5..18c642b1cd67f 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1,4 +1,6 @@ -import { getExportInfos, getImportFixes, getSymbolNamesToImport, shouldUseRequire } from "../services/codefixes/importFixes"; +import { info } from "console"; +import { FormatContext } from "../services/_namespaces/ts.formatting"; +import { FixInfo, ImportFixWithModuleSpecifier, getFixesInfoForNonUMDImport, sortFixInfo } from "../services/codefixes/importFixes"; import * as ts from "./_namespaces/ts"; import { addRange, @@ -21,6 +23,7 @@ import { containsPath, createCacheableExportInfoMap, createLanguageService, + createPackageJsonImportFilter, createResolutionCache, createSymlinkCache, Debug, @@ -66,6 +69,7 @@ import { HasInvalidatedLibResolutions, HasInvalidatedResolutions, HostCancellationToken, + ImportClause, inferredTypesContainingFile, InstallPackageOptions, IScriptSnapshot, @@ -121,6 +125,7 @@ import { StringLiteralLike, stripQuotes, StructureIsReused, + SymbolExportInfo, SymlinkCache, ThrottledCancellationToken, timestamp, @@ -310,6 +315,63 @@ const enum TypingWatcherType { type TypingWatchers = Map & { isInvoked?: boolean; }; +//========================= +//type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; +const enum ImportFixKind { + UseNamespace, + JsdocTypeImport, + AddToExisting, + AddNew, + PromoteTypeOnly, +} +const enum AddAsTypeOnly { + Allowed = 1 << 0, + Required = 1 << 1, + NotAllowed = 1 << 2, +} +// interface FixInfo { +// readonly fix: ImportFix; +// readonly symbolName: string; +// readonly errorIdentifierText: string | undefined; +// readonly isJsxNamespaceFix?: boolean; +// } +type ImportFix = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport | FixPromoteTypeOnlyImport; +interface ImportFixBase { + readonly isReExport?: boolean; + readonly exportInfo?: SymbolExportInfo; + readonly moduleSpecifier: string; +} +interface Qualification { + readonly usagePosition: number; + readonly namespacePrefix: string; +} +interface FixUseNamespaceImport extends ImportFixBase, Qualification { + readonly kind: ImportFixKind.UseNamespace; +} +interface FixAddJsdocTypeImport extends ImportFixBase { + readonly kind: ImportFixKind.JsdocTypeImport; + readonly usagePosition: number; + readonly isReExport: boolean; + readonly exportInfo: SymbolExportInfo; +} +interface FixAddToExistingImport extends ImportFixBase { + readonly kind: ImportFixKind.AddToExisting; + readonly importClauseOrBindingPattern: ImportClause | ts.ObjectBindingPattern; + readonly importKind: ts.ImportKind.Default | ts.ImportKind.Named; + readonly addAsTypeOnly: AddAsTypeOnly; +} +interface FixAddNewImport extends ImportFixBase { + readonly kind: ImportFixKind.AddNew; + readonly importKind: ts.ImportKind; + readonly addAsTypeOnly: AddAsTypeOnly; + readonly useRequire: boolean; + readonly qualification?: Qualification; +} +interface FixPromoteTypeOnlyImport { + readonly kind: ImportFixKind.PromoteTypeOnly; + readonly typeOnlyAliasDeclaration: ts.TypeOnlyAliasDeclaration; +} +//========================= export abstract class Project implements LanguageServiceHost, ModuleResolutionHost { private rootFiles: ScriptInfo[] = []; private rootFilesMap = new Map(); @@ -2230,7 +2292,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo // } /** @internal */ - updatedTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: ts.Program | undefined} { + updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: ts.Program | undefined} { const originalProgram = this.program; this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length-1, pastedText); this.updateGraph(); @@ -2238,8 +2300,16 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const updatedProgram = this.program; return { updatedFile, updatedProgram, originalProgram }; } + + /** @internal */ + revertUpdatedFile(rootFile: string, updatedText: string, originalText: string) { + this.getScriptInfo(rootFile)?.editContent(0, updatedText.length-1, originalText); + this.updateGraph(); + } + + /** @internal */ - getFakeSourceFile(rootFile: string, pastedText: string, _targetFileName: string, targetFileText: string): [] | undefined { + getFakeSourceFile(rootFile: string, formatContext: FormatContext, updatedFile?: SourceFile, updatedProgram?: Program, originalProgram?: Program): FixInfo[] { /** * cscriptInfo.editContent() @@ -2248,16 +2318,17 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo */ //const t = this.getScriptInfo(rootFile); // const scriptInfo = this.projectService.getScriptInfoForPath(this.toPath(rootFile)); - this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length, pastedText); - this.updateGraph(); - const updatedFile = this.program?.getSourceFile(rootFile); - const updatedProgram = this.program; + //this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length, pastedText); + //this.updateGraph(); + //const updatedFile = this.program?.getSourceFile(rootFile); + //const updatedProgram = this.program; - const originalProgram = this.program; + //const originalProgram = this.program; const cancellationToken = this.cancellationToken; const languageServiceHost = this; const preferences = this.projectService.getPreferences(toNormalizedPath(rootFile)); - let allImports:[] | undefined; + let imports: FixInfo[] =[]; + let allImports; if (updatedFile && updatedProgram && originalProgram) { ts.forEachChild(updatedFile, function cb(node) { @@ -2265,19 +2336,15 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo if (!updatedProgram.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ true) && !originalProgram?.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ false)) { //generate imports - const imports = flatMap(getSymbolNamesToImport(updatedFile, originalProgram.getTypeChecker(), node, originalProgram.getCompilerOptions()), symbolName => { - // "default" is a keyword and not a legal identifier for the import, but appears as an identifier. - if (symbolName === ts.InternalSymbolName.Default) { - return undefined; - } - const isValidTypeOnlyUseSite = ts.isValidTypeOnlyAliasUseSite(node); - const useRequire = shouldUseRequire(updatedFile, originalProgram); - const exportInfo = getExportInfos(symbolName, ts.isJSXTagName(node), ts.getMeaningFromLocation(node), cancellationToken, updatedFile, originalProgram, true, languageServiceHost, preferences); - const t = arrayFrom( - ts.flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(updatedFile), isValidTypeOnlyUseSite, useRequire, originalProgram, updatedFile, languageServiceHost, preferences).fixes), - fix => ({ fix, symbolName, errorIdentifierText: node.text, isJsxNamespaceFix: symbolName !== node.text }), - ); - }); + /** + * getImportFixes needs to be called separately and no flat Map is required. + * the 'fix' can be added to something like an array that can be returned and then done something with changes + * *****none of the flatMaps are required***** + */ + const info = tempFunc(updatedFile, updatedProgram, originalProgram, node, languageServiceHost, cancellationToken, preferences, formatContext); + if (info) { + imports = imports.concat(info); + } } } else { @@ -2285,54 +2352,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } }); } - - // const program: Program = ts.createProgram([rootFile], this.getCompilerOptions(), { - // getSourceFile:() => ts.createSourceFile("fake source file", pastedText, { languageVersion: ts.ScriptTarget.ES2015, jsDocParsingMode: JSDocParsingMode.ParseNone }, /*setParentNodes*/ false), - // getDefaultLibFileName: () => ts.getDefaultLibFilePath(this.getCompilerOptions()), - // writeFile: noop, - // getCurrentDirectory: () => this.getCurrentDirectory(), - // getCanonicalFileName: () => "fake source file", - // useCaseSensitiveFileNames: () => true, - // getNewLine: () => "\n", - // fileExists(){return true}, - // readFile() { - // return pastedText; - // } - // }); - // const fakeSourceFile = program.getSourceFile("fake source file"); - // const originalProgram = this.program; - // const cancellationToken = this.cancellationToken; - // const languageServiceHost = this; - // const preferences = this.projectService.getPreferences(toNormalizedPath(rootFile)); - // let imports; - - // if (fakeSourceFile && originalProgram) { - // ts.forEachChild(fakeSourceFile, function cb(node) { - // if (ts.isIdentifier(node)) { - // if (!program.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ true) && - // !originalProgram?.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ false)) { - // //generate imports - // imports = flatMap(getSymbolNamesToImport(fakeSourceFile, originalProgram.getTypeChecker(), node, originalProgram.getCompilerOptions()), symbolName => { - // // "default" is a keyword and not a legal identifier for the import, but appears as an identifier. - // if (symbolName === ts.InternalSymbolName.Default) { - // return undefined; - // } - // const isValidTypeOnlyUseSite = ts.isValidTypeOnlyAliasUseSite(node); - // const useRequire = shouldUseRequire(fakeSourceFile, originalProgram); - // const exportInfo = getExportInfos(symbolName, ts.isJSXTagName(node), ts.getMeaningFromLocation(node), cancellationToken, fakeSourceFile, originalProgram, true, languageServiceHost, preferences); - // return arrayFrom( - // ts.flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(fakeSourceFile), isValidTypeOnlyUseSite, useRequire, program, fakeSourceFile, languageServiceHost, preferences).fixes), - // fix => ({ fix, symbolName, errorIdentifierText: node.text, isJsxNamespaceFix: symbolName !== node.text }), - // ); - // }); - // } - // } - // else { - // node.forEachChild(cb); - // } - // }); - // } - return allImports; + return imports; } /** @internal */ @@ -2352,6 +2372,30 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } } +function tempFunc(updatedFile: SourceFile, updatedProgram: Program, originalProgram: Program, node: ts.Identifier, languageServiceHost: Project, cancellationToken: ts.CancellationToken, preferences: ts.UserPreferences, formatContext: FormatContext): +readonly FixInfo[] | undefined { + if (!updatedProgram.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ true) && + !originalProgram?.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ false)) { + //generate imports + /** + * getImportFixes needs to be called separately and no flat Map is required. + * the 'fix' can be added to something like an array that can be returned and then done something with changes + * *****none of the flatMaps are required***** + */ + const t: ts.CodeFixContextBase = { + sourceFile: updatedFile, + program: originalProgram, + cancellationToken: cancellationToken, + host: languageServiceHost, + preferences: preferences, + formatContext: formatContext + } + const info = getFixesInfoForNonUMDImport(t, node, true); + const packageJsonImportFilter = createPackageJsonImportFilter(updatedFile, preferences, languageServiceHost); + return info && sortFixInfo(info,updatedFile, updatedProgram, packageJsonImportFilter, languageServiceHost); + } +} + function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: Map): SortedReadonlyArray { const sourceFiles = program.getSourceFiles(); tracing?.push(tracing.Phase.Session, "getUnresolvedImports", { count: sourceFiles.length }); diff --git a/src/server/protocol.ts b/src/server/protocol.ts index fe99eb2440307..378d455a7cabe 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -651,7 +651,10 @@ export type GetPostPasteImportFixesRequestArgs = FileLocationOrRangeRequestArgs copyRange?: CopyRange } export interface GetPostPasteImportFixesResponse extends Response { - filename: string; + body: PostPasteImportAction[]; +} +export interface PostPasteImportAction { + edits: FileCodeEdits[]; } /** diff --git a/src/server/session.ts b/src/server/session.ts index bfb054f1c5a7c..510a301249685 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -106,6 +106,7 @@ import { perfLogger, PerformanceEvent, PossibleProgramFileInfo, + PostPasteImportFixes, Program, QuickInfo, RefactorEditInfo, @@ -2796,10 +2797,23 @@ export class Session implements EventSender { return project.getLanguageService().getMoveToRefactoringFileSuggestions(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file)); } - private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs) { + private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction[] { const { file, project } = this.getFileAndProject(args); const textRange = this.getRange(args.pastes[0].range, project.getScriptInfoForNormalizedPath(file)!); - return project.getLanguageService().getPostPasteImportFixes(args.targetFile, [{text: args.pastes[0].text, range: textRange}], this.getPreferences(file), this.getFormatOptions(file), args.originalFile, args.copyRange); + const result = project.getLanguageService().getPostPasteImportFixes(args.targetFile, [{text: args.pastes[0].text, range: textRange}], this.getPreferences(file), this.getFormatOptions(file), args.originalFile, args.copyRange); + // const seenFiles = new Set(); + // const textChanges: FileTextChanges[] = []; + // for (const textChange of projectTextChanges) { + // if (!seenFiles.has(textChange.fileName)) { + // textChanges.push(textChange); + // } + // } + if (result === undefined) { + return []; + } + const allResults = result.map(postPasteAction => this.mapPostPasteAction(postPasteAction)); + + return allResults; } private organizeImports(args: protocol.OrganizeImportsRequestArgs, simplifiedResult: boolean): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { @@ -2934,6 +2948,10 @@ export class Session implements EventSender { return { fixName, description, changes: this.mapTextChangesToCodeEdits(changes), commands, fixId, fixAllDescription }; } + private mapPostPasteAction({ changes }: PostPasteImportFixes): protocol.PostPasteImportAction { + return { edits: this.mapTextChangesToCodeEdits(changes)}; + } + private mapTextChangesToCodeEdits(textChanges: readonly FileTextChanges[]): protocol.FileCodeEdits[] { return textChanges.map(change => this.mapTextChangeToCodeEdit(change)); } diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 295fc31b62c5d..f684c75cd8da0 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -474,7 +474,7 @@ const enum AddAsTypeOnly { NotAllowed = 1 << 2, } type ImportFix = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport | FixPromoteTypeOnlyImport; -type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; +export type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; // Properties are be undefined if fix is derived from an existing import interface ImportFixBase { @@ -974,7 +974,7 @@ function newImportInfoFromExistingSpecifier( } } -interface FixInfo { +export interface FixInfo { readonly fix: ImportFix; readonly symbolName: string; readonly errorIdentifierText: string | undefined; @@ -1002,7 +1002,7 @@ function getFixInfos(context: CodeFixContextBase, errorCode: number, pos: number return info && sortFixInfo(info, context.sourceFile, context.program, packageJsonImportFilter, context.host); } -function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] { +export function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] { const _toPath = (fileName: string) => toPath(fileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host)); return sort(fixes, (a, b) => compareBooleans(!!a.isJsxNamespaceFix, !!b.isJsxNamespaceFix) || @@ -1169,7 +1169,7 @@ function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOp } } -function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { +export function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { const checker = program.getTypeChecker(); const compilerOptions = program.getCompilerOptions(); return flatMap(getSymbolNamesToImport(sourceFile, checker, symbolToken, compilerOptions), symbolName => { @@ -1309,7 +1309,7 @@ function codeActionForFix( }); return createCodeFixAction(importFixName, changes, diag, importFixId, Diagnostics.Add_all_missing_imports); } -function codeActionForFixWorker( +export function codeActionForFixWorker( changes: textChanges.ChangeTracker, sourceFile: SourceFile, symbolName: string, diff --git a/src/services/postPasteImportFix.ts b/src/services/postPasteImportFix.ts index 0484322259dcb..1b905b854908c 100644 --- a/src/services/postPasteImportFix.ts +++ b/src/services/postPasteImportFix.ts @@ -1,9 +1,10 @@ -import { addRange, append } from "../compiler/core"; -import { SourceFile, Statement, UserPreferences, TypeChecker, AnyImportOrRequireStatement, Identifier, ModifierFlags, Program, TextRange } from "../compiler/types"; -import { hasSyntacticModifier, skipAlias } from "../compiler/utilities"; -import { codefix, factory, fileShouldUseJavaScriptRequire, formatting, getLineInfo, getQuotePreference, insertImports, nodeSeenTracker, Symbol, textChanges } from "./_namespaces/ts"; +import { addRange, append, arrayFrom, flatMap, flatMapIterator } from "../compiler/core"; +import { SourceFile, Statement, UserPreferences, TypeChecker, AnyImportOrRequireStatement, Identifier, ModifierFlags, Program, TextRange, CancellationToken, InternalSymbolName, ImportClause, ObjectBindingPattern, TypeOnlyAliasDeclaration } from "../compiler/types"; +import { hasSyntacticModifier, isJSXTagName, isValidTypeOnlyAliasUseSite, skipAlias } from "../compiler/utilities"; +import { codefix, Debug, DiagnosticOrDiagnosticAndArguments, factory, fileShouldUseJavaScriptRequire, formatting, getMeaningFromLocation, getQuotePreference, ImportKind, insertImports, nodeSeenTracker, Symbol, SymbolExportInfo, textChanges } from "./_namespaces/ts"; +import { getSymbolNamesToImport, shouldUseRequire, getExportInfos, getImportFixes, codeActionForFixWorker } from "./codefixes/importFixes"; import { addExportToChanges, filterImport, forEachImportInStatement, getTopLevelDeclarationStatement, getUsageInfo, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./refactors/moveToFile"; -import { CopyRange, FileTextChanges, LanguageServiceHost } from "./types"; +import { CopyRange, FileTextChanges, LanguageServiceHost, PostPasteImportFixes } from "./types"; /** @internal */ export function postPastImportFixProvider( @@ -13,7 +14,7 @@ export function postPastImportFixProvider( preferences: UserPreferences, formatContext: formatting.FormatContext, originalFile?: SourceFile, - copyLocation?: CopyRange): FileTextChanges[] { + copyLocation?: CopyRange): PostPasteImportFixes[] { /** * When the source file exists @@ -21,32 +22,57 @@ export function postPastImportFixProvider( * 2.use getUsageInfo() to the symbols that need to be imported * 3.use the if and the third part of getTargetFileImportsAndAddExportInOldFile * */ - const { updatedFile, updatedProgram, originalProgram } = host.updatedTargetFile(targetFile.fileName, targetFile.text, pastes[0].text); + //const originalText = targetFile.text; + const { updatedFile, updatedProgram, originalProgram } = host.updateTargetFile(targetFile.fileName, targetFile.text, pastes[0].text); let statements: Statement[] = []; if (originalFile && originalProgram && updatedFile && updatedProgram) { - //addRange(statements, updatedFile?.statements, updatedFile?.statements.length - (targetFileStatements ? targetFileStatements.length : 0) - 1); - //addRange(statements, originalFile?.statements, 2); - //const start = originalFile.statements[0].getStart(originalFile);//addRange(statements, originalFile.statements, updatedFile.statements[updatedFile.statements.length - targetFileStatements.length].getStart(originalFile)) - - //addRange(statements, updatedFile.statements, a.getStart(originalFile), b.getStart(originalFile)); - // const a = updatedFile.statements[updatedFile.getLineAndCharacterOfPosition(pastes[0].range.pos).line] //21 - // const b = updatedFile.statements[updatedFile.getLineAndCharacterOfPosition(pastes[0].range.end).line] //pastes[0].range.end + pastes[0].range.length - 1 - addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation?.end.line); + addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation ? copyLocation.end.line + 1 : undefined); const usage = getUsageInfo(originalFile, statements, originalProgram.getTypeChecker()); const importAdder = codefix.createImportAdder(updatedFile, updatedProgram, preferences, host); - return textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => getImports(originalFile, updatedFile, statements, updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, - usage.targetFileImportsFromOldFile, changeTracker, preferences, host, updatedProgram.getTypeChecker())); + const changes = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => getImports(originalFile, updatedFile, statements, updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, + usage.targetFileImportsFromOldFile, changeTracker, preferences, host, originalProgram.getTypeChecker())); + host.revertUpdatedFile(targetFile.fileName, updatedFile.text, targetFile.text); + return [{changes}]; } else { - return []; + Debug.assert(updatedFile !== undefined && originalProgram !== undefined); + Debug.assert(updatedProgram !== undefined); + const fixInfo = host.getFakeSourceFile(targetFile.fileName, formatContext, updatedFile, updatedProgram, originalProgram); + const fixes = fixInfo.map(({fix, symbolName}) => getImportsForUnknownSourceFile( + { host, formatContext, preferences }, + updatedFile, + symbolName, + fix, + true, + updatedProgram, + preferences, + )); + host.revertUpdatedFile(targetFile.fileName, updatedFile.text, targetFile.text); + return fixes; } //const unknownSymbols = host.getFakeSourceFile(targetFile,pastes[0].text,targetFile, targetFileText); } +function getImportsForUnknownSourceFile( + context: textChanges.TextChangesContext, + sourceFile: SourceFile, + symbolName: string, + fix: codefix.FixInfo["fix"], + includeSymbolNameInDescription: boolean, + program: Program, + preferences: UserPreferences, +): PostPasteImportFixes { + let diag!: DiagnosticOrDiagnosticAndArguments; + const changes = textChanges.ChangeTracker.with(context, tracker => { + diag = codeActionForFixWorker(tracker, sourceFile, symbolName, fix, includeSymbolNameInDescription, program, preferences); + }); + return {changes}; +} + function getImports( originalFile: SourceFile, targetFile: SourceFile, @@ -128,3 +154,78 @@ function getTargetFileImportsForKnownOriginalFile( return append(copiedOldImports, makeImportOrRequire(targetFile, oldFileDefault, oldFileNamedImports, originalFile.fileName, program, host, useEsModuleSyntax, quotePreference)) } +// interface FixInfo { +// readonly fix: ImportFix; +// readonly symbolName: string; +// readonly errorIdentifierText: string | undefined; +// readonly isJsxNamespaceFix?: boolean; +// } +// export function tempFunction(updatedFile: SourceFile, originalProgram: Program, node: Identifier, languageServiceHost: LanguageServiceHost, cancellationToken: CancellationToken, preferences: UserPreferences) { +// return flatMap(getSymbolNamesToImport(updatedFile, originalProgram.getTypeChecker(), node, originalProgram.getCompilerOptions()), symbolName => { +// // "default" is a keyword and not a legal identifier for the import, but appears as an identifier. +// if (symbolName === InternalSymbolName.Default) { +// return undefined; +// } +// const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite(node); +// const useRequire = shouldUseRequire(updatedFile, originalProgram); +// const exportInfo = getExportInfos(symbolName, isJSXTagName(node), getMeaningFromLocation(node), cancellationToken, updatedFile, originalProgram, true, languageServiceHost, preferences); +// //const t1 = exportInfo.values(); +// //const fix = ts.flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(updatedFile), isValidTypeOnlyUseSite, useRequire, originalProgram, updatedFile, languageServiceHost, preferences).fixes); +// return arrayFrom( +// flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(updatedFile), isValidTypeOnlyUseSite, useRequire, originalProgram, updatedFile, languageServiceHost, preferences).fixes), +// fix => ({ fix, symbolName, errorIdentifierText: node.text, isJsxNamespaceFix: symbolName !== node.text }), +// ); +// }); + +// } + +// type ImportFix = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport | FixPromoteTypeOnlyImport; +// type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; + +const enum ImportFixKind { + UseNamespace, + JsdocTypeImport, + AddToExisting, + AddNew, + PromoteTypeOnly, +} +interface ImportFixBase { + readonly isReExport?: boolean; + readonly exportInfo?: SymbolExportInfo; + readonly moduleSpecifier: string; +} +const enum AddAsTypeOnly { + Allowed = 1 << 0, + Required = 1 << 1, + NotAllowed = 1 << 2, +} +interface FixPromoteTypeOnlyImport { + readonly kind: ImportFixKind.PromoteTypeOnly; + readonly typeOnlyAliasDeclaration: TypeOnlyAliasDeclaration; +} +interface Qualification { + readonly usagePosition: number; + readonly namespacePrefix: string; +} +interface FixUseNamespaceImport extends ImportFixBase, Qualification { + readonly kind: ImportFixKind.UseNamespace; +} +// interface FixAddJsdocTypeImport extends ImportFixBase { +// readonly kind: ImportFixKind.JsdocTypeImport; +// readonly usagePosition: number; +// readonly isReExport: boolean; +// readonly exportInfo: SymbolExportInfo; +// } +interface FixAddToExistingImport extends ImportFixBase { + readonly kind: ImportFixKind.AddToExisting; + readonly importClauseOrBindingPattern: ImportClause | ObjectBindingPattern; + readonly importKind: ImportKind.Default | ImportKind.Named; + readonly addAsTypeOnly: AddAsTypeOnly; +} +interface FixAddNewImport extends ImportFixBase { + readonly kind: ImportFixKind.AddNew; + readonly importKind: ImportKind; + readonly addAsTypeOnly: AddAsTypeOnly; + readonly useRequire: boolean; + readonly qualification?: Qualification; +} \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index e6a90ad61c966..f3581f6a1a0ad 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -321,6 +321,7 @@ import { VariableDeclaration, postPasteImportFixes, CopyRange, + PostPasteImportFixes, } from "./_namespaces/ts"; import * as NavigateTo from "./_namespaces/ts.NavigateTo"; import * as NavigationBar from "./_namespaces/ts.NavigationBar"; @@ -2098,7 +2099,7 @@ export function createLanguageService( formatOptions: FormatCodeSettings, originalFile?: string, copyLocation?: CopyRange - ): FileTextChanges[]{ + ): PostPasteImportFixes[]{ synchronizeHostData(); const originalSourceFile = originalFile ? getValidSourceFile(originalFile) : undefined; const edits = postPasteImportFixes.postPastImportFixProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host), originalSourceFile, copyLocation); diff --git a/src/services/types.ts b/src/services/types.ts index b40afb2f71d6e..60f7f53076a3b 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -42,6 +42,8 @@ import { TextSpan, UserPreferences, } from "./_namespaces/ts"; +import { FixInfo } from "./_namespaces/ts.codefix"; +import { FormatContext } from "./formatting/formatting"; declare module "../compiler/types" { // Module transform: converted from interface augmentation @@ -431,8 +433,9 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; /** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; - /** @internal */ getFakeSourceFile(rootFile: string, pastedText: string, targetFileName: string, targetFileText: string) : [] | undefined; - /** @internal */ updatedTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: Program | undefined}; + /** @internal */ getFakeSourceFile(rootFile: string, formatContext: FormatContext, updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: Program | undefined): FixInfo[]; + /** @internal */ updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: Program | undefined}; + /** @internal */ revertUpdatedFile(rootFile: string, updatedText: string, originalText: string): void; //needs to be changed to optional jsDocParsingMode?: JSDocParsingMode | undefined; } @@ -686,7 +689,7 @@ export interface LanguageService { getSupportedCodeFixes(fileName?: string): readonly string[]; dispose(): void; - getPostPasteImportFixes (targetFile: string, pastes: Array<{text: string; range: TextRange}>, preferences: UserPreferences, formatOptions: FormatCodeSettings, originalFile: string | undefined, copyLocation: CopyRange | undefined): FileTextChanges[]; + getPostPasteImportFixes (targetFile: string, pastes: Array<{text: string; range: TextRange}>, preferences: UserPreferences, formatOptions: FormatCodeSettings, originalFile: string | undefined, copyLocation: CopyRange | undefined): PostPasteImportFixes[]; } export interface CopyRange { @@ -714,10 +717,11 @@ export const enum OrganizeImportsMode { RemoveUnused = "RemoveUnused", } -export interface postPasteImportFix { - targetFile: string, - targetFileText: string, - pastes: Array<{text: string; range: TextSpan}> +export interface PostPasteImportFixes { + // targetFile: string, + // targetFileText: string, + // pastes: Array<{text: string; range: TextSpan}> + changes: FileTextChanges[]; } export interface OrganizeImportsArgs extends CombinedCodeFixScope { diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 6722b3ef4b31e..105430b8d9feb 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -453,6 +453,7 @@ declare namespace FourSlashInterface { commentSelection(newFileContent: string): void; uncommentSelection(newFileContent: string): void; postPasteImportFix(options: { + newFileContents: { readonly [fileName: string]: string }; targetFile: string, pastes: Array<{text: string; range: {pos: number, end: number}}> originalFile?: string, diff --git a/tests/cases/fourslash/server/postPasteImportFix1.ts b/tests/cases/fourslash/server/postPasteImportFix1.ts index 2918b3d89a660..9f86b05928142 100644 --- a/tests/cases/fourslash/server/postPasteImportFix1.ts +++ b/tests/cases/fourslash/server/postPasteImportFix1.ts @@ -1,18 +1,19 @@ /// -// @Filename: file1.ts +// @Filename: /file1.ts //// export interface Test1 {} //// export interface Test2 {} //// export interface Test3 {} //// export interface Test4 {} -// @Filename: file2.ts +// @Filename: /file2.ts //// /*a*/const a = 10;/*b*/ -// @Filename: tsconfig.json +// @Filename: /tsconfig.json ////{ "files": ["file1.ts", "file2.ts"] } goTo.select("a", "b"); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFix({ targetFile: "file2.ts", pastes: [{ @@ -23,6 +24,18 @@ verify.postPasteImportFix({ test3: Test3; test4: Test4; }`, - range: { pos: 0, end: 54 }, + range: { pos: 0, end: 12 }, }], + newFileContents: { + "/file2.ts": +`import { Test1, Test2, Test3, Test4 } from './file1' + +const a = 10; +interface Testing { + test1: Test1; + test2: Test2; + test3: Test3; + test4: Test4; +}` + } }); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix3.ts b/tests/cases/fourslash/server/postPasteImportFix3.ts index 2472277f67f65..c51259a35b45a 100644 --- a/tests/cases/fourslash/server/postPasteImportFix3.ts +++ b/tests/cases/fourslash/server/postPasteImportFix3.ts @@ -1,22 +1,23 @@ /// -// @Filename: file1.ts +// @Filename: /file1.ts ////export const b = 2; -// @Filename: file2.ts -////import { b } from './other'; +// @Filename: /file2.ts +////import { b } from './file1'; ////const a = 1; ////const c = a + b; ////const t = 9; -// @Filename: file3.ts +// @Filename: /file3.ts //// /*a*/export const tt = 2;/*b*/ //// function f(); -// @Filename: tsconfig.json +// @Filename: /tsconfig.json ////{ "files": ["file1.ts", "file2.ts", "file3.ts"] } goTo.select("a", "b"); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFix({ targetFile: "file3.ts", pastes: [{ @@ -24,8 +25,27 @@ verify.postPasteImportFix({ const c = a + b; const t = 9; function f();`, - range: { pos: 20, end: 29 }, + range: { pos: 20, end: 22 }, }], originalFile: "file2.ts", - copyRange: { start: { line : 3, offset: 0}, end : { line: 4, offset: 21}}, + copyRange: { start: { line : 2, offset: 0}, end : { line: 3, offset: 0}}, + newFileContents: { + "/file2.ts": +`import { b } from './file1'; +export const a = 1; +const c = a + b; +const t = 9;`, + + "/file3.ts": +`import { a } from "./file2"; + +import { b } from './file1'; + +export const tt = 2; +function f(); +const c = a + b; +const t = 9; + +`, + } }); \ No newline at end of file From 17f9897a8f00958f8f8c66b80e59c4ffc9b0f2bb Mon Sep 17 00:00:00 2001 From: navya9singh Date: Thu, 1 Feb 2024 10:54:37 -0800 Subject: [PATCH 03/18] Allows different text in each cursor location --- src/harness/client.ts | 28 +-- src/harness/fourslashImpl.ts | 6 +- src/harness/fourslashInterfaceImpl.ts | 2 +- src/server/project.ts | 92 +------- src/server/protocol.ts | 2 +- src/server/session.ts | 16 +- src/services/codefixes/importFixes.ts | 15 +- src/services/postPasteImportFix.ts | 218 +++++------------- src/services/services.ts | 4 +- src/services/types.ts | 10 +- ...portNameCodeFix_add_all_missing_imports.ts | 9 +- .../fourslash/server/postPasteImportFix2.ts | 38 --- ... => postPasteImportFix_knownSourceFile.ts} | 21 +- .../postPasteImportFix_multiplePastes1.ts | 46 ++++ .../postPasteImportFix_multiplePastes2.ts | 50 ++++ ...> postPasteImportFix_unknownSourceFile.ts} | 22 +- 16 files changed, 230 insertions(+), 349 deletions(-) delete mode 100644 tests/cases/fourslash/server/postPasteImportFix2.ts rename tests/cases/fourslash/server/{postPasteImportFix3.ts => postPasteImportFix_knownSourceFile.ts} (69%) create mode 100644 tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts rename tests/cases/fourslash/server/{postPasteImportFix1.ts => postPasteImportFix_unknownSourceFile.ts} (64%) diff --git a/src/harness/client.ts b/src/harness/client.ts index c89433352209d..220cf4548dc0b 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -1,5 +1,6 @@ import { ApplicableRefactorInfo, + arrayFrom, CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, @@ -1011,33 +1012,20 @@ export class SessionClient implements LanguageService { return getSupportedCodeFixes(); } - getPostPasteImportFixes(targetFile: string, pastes: Array<{text: string; range: TextRange}>, _preferences: UserPreferences, _formatOptions: FormatCodeSettings, originalFile?: string, copyRange?: CopyRange): PostPasteImportFixes[]{ - const t = this.createFileRangeRequestArgs(targetFile, pastes[0].range.pos, pastes[0].range.end); - const args = this.createFileLocationOrRangeRequestArgs(pastes[0].range, targetFile) as protocol.GetPostPasteImportFixesRequestArgs; //needs to be fixed + getPostPasteImportFixes(targetFile: string, pastes: Array<{text: string; range: TextRange}>, _preferences: UserPreferences, _formatOptions: FormatCodeSettings, originalFile?: string, copyRange?: CopyRange): PostPasteImportFixes{ + const args = this.createFileLocationOrRangeRequestArgs(pastes[0].range, targetFile) as protocol.GetPostPasteImportFixesRequestArgs; args.targetFile = targetFile; - args.pastes = [{text: pastes[0].text, range: t}]; + args.pastes = arrayFrom(pastes.map(paste => ({text: paste.text, range: this.createFileRangeRequestArgs(targetFile, paste.range.pos, paste.range.end)}))); args.originalFile = originalFile; args.copyRange = copyRange; - + const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); const response = this.processResponse(request); if (!response.body) { - return []; + return { edits: []}; } - - // return response.body!.map(({ fixName, description, changes, commands, fixId, fixAllDescription }) => // TODO: GH#18217 - // ({ fixName, description, changes: this.convertChanges(changes, file), commands: commands as CodeActionCommand[], fixId, fixAllDescription })); - - //const q = response.body.map(({changes}) => ({this.convertChanges(changes, targetFile)})); - //const r: FileTextChanges[] = response.body.map(item =>({changes: this.convertCodeEditsToTextChanges(item.edits)})); - /////////const q = response.body.map(item =>this.convertCodeEditsToTextChanges(item.edits)); - const e = response.body.map(item => ({changes: this.convertCodeEditsToTextChanges(item.edits)})) - // let allEdits: FileTextChanges[] = []; - // for (const edits of response.body) { - // allEdits = this.convertCodeEditsToTextChanges(edits); - // } - // const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body); - return e; + const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body.edits); + return { edits: edits }; } getProgram(): Program { diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 05e9b675a0a63..f138c93fdf45c 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -3554,11 +3554,9 @@ export class TestState { assert.deepEqual(actualModuleSpecifiers, moduleSpecifiers); } - public getPostPasteImportFixes(options: FourSlashInterface.PostPasteImportFixOptions): void{ - const range = this.getSelection(); - //const range: ts.TextRange = {pos: pastes[0].range.pos, end: pastes[0].range.end}; + public verifyPostPasteImportFixes(options: FourSlashInterface.PostPasteImportFixOptions): void{ const editInfo = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, options.pastes, options.preferences, this.formatCodeSettings, options.originalFile, options.copyRange); - this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo[0].changes); + this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits); } public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined, options?: ts.DocCommentTemplateOptions) { diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index a3d92dd98f6d5..f1d97d4661fb0 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -622,7 +622,7 @@ export class Verify extends VerifyNegatable { } public postPasteImportFix(options: PostPasteImportFixOptions): void { - this.state.getPostPasteImportFixes(options); + this.state.verifyPostPasteImportFixes(options); } } diff --git a/src/server/project.ts b/src/server/project.ts index 18c642b1cd67f..0056f6fb6e2d2 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2275,30 +2275,12 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo return this.noDtsResolutionProject; } - // export anotherGetFixes(updatedFile: ts.SourceFile, originalProgram: ts.Program, node: ts.Identifier, languageServiceHost: this, cancellationToken: ts.CancellationToken, preferences: ts.UserPreferences) { - // const imports = flatMap(getSymbolNamesToImport(updatedFile, originalProgram.getTypeChecker(), node, originalProgram.getCompilerOptions()), symbolName => { - // // "default" is a keyword and not a legal identifier for the import, but appears as an identifier. - // if (symbolName === ts.InternalSymbolName.Default) { - // return undefined; - // } - // const isValidTypeOnlyUseSite = ts.isValidTypeOnlyAliasUseSite(node); - // const useRequire = shouldUseRequire(updatedFile, originalProgram); - // const exportInfo = getExportInfos(symbolName, ts.isJSXTagName(node), ts.getMeaningFromLocation(node), cancellationToken, updatedFile, originalProgram, true, languageServiceHost, preferences); - // return arrayFrom( - // ts.flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(updatedFile), isValidTypeOnlyUseSite, useRequire, originalProgram, updatedFile, languageServiceHost, preferences).fixes), - // fix => ({ fix, symbolName, errorIdentifierText: node.text, isJsxNamespaceFix: symbolName !== node.text }), - // ); - // } - // } - /** @internal */ updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: ts.Program | undefined} { const originalProgram = this.program; this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length-1, pastedText); this.updateGraph(); - const updatedFile = this.program?.getSourceFile(rootFile); - const updatedProgram = this.program; - return { updatedFile, updatedProgram, originalProgram }; + return { updatedFile: (this.program?.getSourceFile(rootFile)), updatedProgram: this.program, originalProgram }; } /** @internal */ @@ -2307,54 +2289,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo this.updateGraph(); } - - /** @internal */ - getFakeSourceFile(rootFile: string, formatContext: FormatContext, updatedFile?: SourceFile, updatedProgram?: Program, originalProgram?: Program): FixInfo[] { - - /** - * cscriptInfo.editContent() - * project.updateGraph gives the new SF - * after scriptInfo.editContent("") the new SF is not updated - */ - //const t = this.getScriptInfo(rootFile); - // const scriptInfo = this.projectService.getScriptInfoForPath(this.toPath(rootFile)); - //this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length, pastedText); - //this.updateGraph(); - //const updatedFile = this.program?.getSourceFile(rootFile); - //const updatedProgram = this.program; - - //const originalProgram = this.program; - const cancellationToken = this.cancellationToken; - const languageServiceHost = this; - const preferences = this.projectService.getPreferences(toNormalizedPath(rootFile)); - let imports: FixInfo[] =[]; - let allImports; - - if (updatedFile && updatedProgram && originalProgram) { - ts.forEachChild(updatedFile, function cb(node) { - if (ts.isIdentifier(node)) { - if (!updatedProgram.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ true) && - !originalProgram?.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ false)) { - //generate imports - /** - * getImportFixes needs to be called separately and no flat Map is required. - * the 'fix' can be added to something like an array that can be returned and then done something with changes - * *****none of the flatMaps are required***** - */ - const info = tempFunc(updatedFile, updatedProgram, originalProgram, node, languageServiceHost, cancellationToken, preferences, formatContext); - if (info) { - imports = imports.concat(info); - } - } - } - else { - node.forEachChild(cb); - } - }); - } - return imports; - } - /** @internal */ private getCompilerOptionsForNoDtsResolutionProject() { return { @@ -2372,30 +2306,6 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } } -function tempFunc(updatedFile: SourceFile, updatedProgram: Program, originalProgram: Program, node: ts.Identifier, languageServiceHost: Project, cancellationToken: ts.CancellationToken, preferences: ts.UserPreferences, formatContext: FormatContext): -readonly FixInfo[] | undefined { - if (!updatedProgram.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ true) && - !originalProgram?.getTypeChecker().resolveName(node.text, node, ts.SymbolFlags.All, /*excludeGlobals*/ false)) { - //generate imports - /** - * getImportFixes needs to be called separately and no flat Map is required. - * the 'fix' can be added to something like an array that can be returned and then done something with changes - * *****none of the flatMaps are required***** - */ - const t: ts.CodeFixContextBase = { - sourceFile: updatedFile, - program: originalProgram, - cancellationToken: cancellationToken, - host: languageServiceHost, - preferences: preferences, - formatContext: formatContext - } - const info = getFixesInfoForNonUMDImport(t, node, true); - const packageJsonImportFilter = createPackageJsonImportFilter(updatedFile, preferences, languageServiceHost); - return info && sortFixInfo(info,updatedFile, updatedProgram, packageJsonImportFilter, languageServiceHost); - } -} - function getUnresolvedImports(program: Program, cachedUnresolvedImportsPerFile: Map): SortedReadonlyArray { const sourceFiles = program.getSourceFiles(); tracing?.push(tracing.Phase.Session, "getUnresolvedImports", { count: sourceFiles.length }); diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 378d455a7cabe..3d957c3f0db7e 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -651,7 +651,7 @@ export type GetPostPasteImportFixesRequestArgs = FileLocationOrRangeRequestArgs copyRange?: CopyRange } export interface GetPostPasteImportFixesResponse extends Response { - body: PostPasteImportAction[]; + body: PostPasteImportAction; } export interface PostPasteImportAction { edits: FileCodeEdits[]; diff --git a/src/server/session.ts b/src/server/session.ts index 510a301249685..62fe53833ad75 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2797,10 +2797,11 @@ export class Session implements EventSender { return project.getLanguageService().getMoveToRefactoringFileSuggestions(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file)); } - private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction[] { + private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction | undefined { const { file, project } = this.getFileAndProject(args); - const textRange = this.getRange(args.pastes[0].range, project.getScriptInfoForNormalizedPath(file)!); - const result = project.getLanguageService().getPostPasteImportFixes(args.targetFile, [{text: args.pastes[0].text, range: textRange}], this.getPreferences(file), this.getFormatOptions(file), args.originalFile, args.copyRange); + //const pastes: Array<{text: string; range: TextRange}> = arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange(paste.range, project.getScriptInfoForNormalizedPath(file)!)})); + //const textRange = this.getRange(args.pastes[0].range, project.getScriptInfoForNormalizedPath(file)!); + const result = project.getLanguageService().getPostPasteImportFixes(args.targetFile, arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange(paste.range, project.getScriptInfoForNormalizedPath(file)!)})), this.getPreferences(file), this.getFormatOptions(file), args.originalFile, args.copyRange); // const seenFiles = new Set(); // const textChanges: FileTextChanges[] = []; // for (const textChange of projectTextChanges) { @@ -2809,9 +2810,10 @@ export class Session implements EventSender { // } // } if (result === undefined) { - return []; + return undefined; } - const allResults = result.map(postPasteAction => this.mapPostPasteAction(postPasteAction)); + //const allResults = result.map(postPasteAction => this.mapPostPasteAction(postPasteAction)); + const allResults = this.mapPostPasteAction(result); return allResults; } @@ -2948,8 +2950,8 @@ export class Session implements EventSender { return { fixName, description, changes: this.mapTextChangesToCodeEdits(changes), commands, fixId, fixAllDescription }; } - private mapPostPasteAction({ changes }: PostPasteImportFixes): protocol.PostPasteImportAction { - return { edits: this.mapTextChangesToCodeEdits(changes)}; + private mapPostPasteAction({ edits }: PostPasteImportFixes): protocol.PostPasteImportAction { + return { edits: this.mapTextChangesToCodeEdits(edits)}; } private mapTextChangesToCodeEdits(textChanges: readonly FileTextChanges[]): protocol.FileCodeEdits[] { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index f684c75cd8da0..0e1131f6ef91f 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -212,6 +212,7 @@ export interface ImportAdder { addImportFromDiagnostic: (diagnostic: DiagnosticWithLocation, context: CodeFixContextBase) => void; addImportFromExportedSymbol: (exportedSymbol: Symbol, isValidTypeOnlyUseSite?: boolean) => void; writeFixes: (changeTracker: textChanges.ChangeTracker, oldFileQuotePreference?: QuotePreference) => void; + addImportsForUnknownSymbols: (context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean) => void; } /** @internal */ @@ -236,8 +237,14 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu type NewImportsKey = `${0 | 1}|${string}`; /** Use `getNewImportEntry` for access */ const newImports = new Map>(); - return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes }; + return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes, addImportsForUnknownSymbols }; + function addImportsForUnknownSymbols(context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean) { + const info = getFixInfosWithoutDiagnostic(context, symbolToken, useAutoImportProvider); + if (!info || !info.length) return; + addImport(first(info)); + } + function addImportFromDiagnostic(diagnostic: DiagnosticWithLocation, context: CodeFixContextBase) { const info = getFixInfos(context, diagnostic.code, diagnostic.start, useAutoImportProvider); if (!info || !info.length) return; @@ -1010,6 +1017,12 @@ export function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModul compareModuleSpecifiers(a.fix, b.fix, sourceFile, program, packageJsonImportFilter.allowsImportingSpecifier, _toPath)); } +function getFixInfosWithoutDiagnostic(context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly FixInfo[] | undefined { + const info = getFixesInfoForNonUMDImport(context, symbolToken, useAutoImportProvider); + const packageJsonImportFilter = createPackageJsonImportFilter(context.sourceFile, context.preferences, context.host); + return info && sortFixInfo(info, context.sourceFile, context.program, packageJsonImportFilter, context.host); +} + function getBestFix(fixes: readonly ImportFixWithModuleSpecifier[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): ImportFixWithModuleSpecifier | undefined { if (!some(fixes)) return; // These will always be placed first if available, and are better than other kinds diff --git a/src/services/postPasteImportFix.ts b/src/services/postPasteImportFix.ts index 1b905b854908c..7c0340d1ea715 100644 --- a/src/services/postPasteImportFix.ts +++ b/src/services/postPasteImportFix.ts @@ -1,10 +1,9 @@ -import { addRange, append, arrayFrom, flatMap, flatMapIterator } from "../compiler/core"; -import { SourceFile, Statement, UserPreferences, TypeChecker, AnyImportOrRequireStatement, Identifier, ModifierFlags, Program, TextRange, CancellationToken, InternalSymbolName, ImportClause, ObjectBindingPattern, TypeOnlyAliasDeclaration } from "../compiler/types"; -import { hasSyntacticModifier, isJSXTagName, isValidTypeOnlyAliasUseSite, skipAlias } from "../compiler/utilities"; -import { codefix, Debug, DiagnosticOrDiagnosticAndArguments, factory, fileShouldUseJavaScriptRequire, formatting, getMeaningFromLocation, getQuotePreference, ImportKind, insertImports, nodeSeenTracker, Symbol, SymbolExportInfo, textChanges } from "./_namespaces/ts"; -import { getSymbolNamesToImport, shouldUseRequire, getExportInfos, getImportFixes, codeActionForFixWorker } from "./codefixes/importFixes"; +import { addRange, append } from "../compiler/core"; +import { SourceFile, Statement, UserPreferences, TypeChecker, AnyImportOrRequireStatement, Identifier, ModifierFlags, Program, TextRange, CancellationToken, ImportClause, ObjectBindingPattern, TypeOnlyAliasDeclaration, SymbolFlags } from "../compiler/types"; +import { hasSyntacticModifier, skipAlias } from "../compiler/utilities"; +import { codefix, Debug, factory, fileShouldUseJavaScriptRequire, forEachChild, formatting, getQuotePreference, ImportKind, insertImports, nodeSeenTracker, Symbol, SymbolExportInfo, textChanges, isIdentifier } from "./_namespaces/ts"; import { addExportToChanges, filterImport, forEachImportInStatement, getTopLevelDeclarationStatement, getUsageInfo, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./refactors/moveToFile"; -import { CopyRange, FileTextChanges, LanguageServiceHost, PostPasteImportFixes } from "./types"; +import { CodeFixContextBase, CopyRange, FileTextChanges, LanguageServiceHost, PostPasteImportFixes } from "./types"; /** @internal */ export function postPastImportFixProvider( @@ -13,88 +12,74 @@ export function postPastImportFixProvider( pastes: Array<{text: string; range: TextRange}>, preferences: UserPreferences, formatContext: formatting.FormatContext, + cancellationToken: CancellationToken, originalFile?: SourceFile, - copyLocation?: CopyRange): PostPasteImportFixes[] { + copyLocation?: CopyRange): PostPasteImportFixes { - /** - * When the source file exists - * 1.Need to turn pasted text, in pastes.text into statements - * 2.use getUsageInfo() to the symbols that need to be imported - * 3.use the if and the third part of getTargetFileImportsAndAddExportInOldFile - * */ - //const originalText = targetFile.text; - const { updatedFile, updatedProgram, originalProgram } = host.updateTargetFile(targetFile.fileName, targetFile.text, pastes[0].text); - let statements: Statement[] = []; - - if (originalFile && originalProgram && updatedFile && updatedProgram) { - addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation ? copyLocation.end.line + 1 : undefined); - const usage = getUsageInfo(originalFile, statements, originalProgram.getTypeChecker()); - const importAdder = codefix.createImportAdder(updatedFile, updatedProgram, preferences, host); - - const changes = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => getImports(originalFile, updatedFile, statements, updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, - usage.targetFileImportsFromOldFile, changeTracker, preferences, host, originalProgram.getTypeChecker())); - host.revertUpdatedFile(targetFile.fileName, updatedFile.text, targetFile.text); - return [{changes}]; - } - else { - Debug.assert(updatedFile !== undefined && originalProgram !== undefined); - Debug.assert(updatedProgram !== undefined); - const fixInfo = host.getFakeSourceFile(targetFile.fileName, formatContext, updatedFile, updatedProgram, originalProgram); - const fixes = fixInfo.map(({fix, symbolName}) => getImportsForUnknownSourceFile( - { host, formatContext, preferences }, - updatedFile, - symbolName, - fix, - true, - updatedProgram, - preferences, - )); - host.revertUpdatedFile(targetFile.fileName, updatedFile.text, targetFile.text); - return fixes; - } - - - //const unknownSymbols = host.getFakeSourceFile(targetFile,pastes[0].text,targetFile, targetFileText); + let changes: FileTextChanges[] = []; + changes = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => pastes.forEach(({text, range}) => + { postPasteFixes(targetFile, host, text, range, preferences, formatContext, cancellationToken, changeTracker, originalFile, copyLocation)})); + return { edits: changes }; } -function getImportsForUnknownSourceFile( - context: textChanges.TextChangesContext, - sourceFile: SourceFile, - symbolName: string, - fix: codefix.FixInfo["fix"], - includeSymbolNameInDescription: boolean, - program: Program, +function postPasteFixes ( + targetFile: SourceFile, + host: LanguageServiceHost, + pastedText: string, + pastedRange: TextRange, preferences: UserPreferences, -): PostPasteImportFixes { - let diag!: DiagnosticOrDiagnosticAndArguments; - const changes = textChanges.ChangeTracker.with(context, tracker => { - diag = codeActionForFixWorker(tracker, sourceFile, symbolName, fix, includeSymbolNameInDescription, program, preferences); - }); - return {changes}; -} - -function getImports( - originalFile: SourceFile, - targetFile: SourceFile, - statements: Statement[], - program: Program, - importAdder: codefix.ImportAdder, - importsToCopy: Map, - targetFileImportsFromOldFile: Set, + formatContext: formatting.FormatContext, + cancellationToken: CancellationToken, changes: textChanges.ChangeTracker, - preferences: UserPreferences, - host: LanguageServiceHost, - checker: TypeChecker) { + originalFile?: SourceFile, + copyLocation?: CopyRange) { + + const updatedTargetFile = host.updateTargetFile?.(targetFile.fileName, targetFile.getText(), targetFile.getText().slice(0, pastedRange.pos) + pastedText + targetFile.getText().slice(0, pastedRange.end)); + let statements: Statement[] = []; + Debug.assert(updatedTargetFile && updatedTargetFile.updatedFile && updatedTargetFile.originalProgram && updatedTargetFile.updatedProgram); + + if (originalFile) { + addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation ? copyLocation.end.line + 1 : undefined); + const usage = getUsageInfo(originalFile, statements, updatedTargetFile.originalProgram.getTypeChecker()); + const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); - const imports = getTargetFileImportsForKnownOriginalFile(originalFile, targetFile, program, importAdder, importsToCopy, targetFileImportsFromOldFile, changes, preferences, host, checker); - if (imports.length > 0) { - insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); + const imports = getImportsFromKnownOriginalFile(originalFile, targetFile, updatedTargetFile.updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, preferences, host, updatedTargetFile.originalProgram.getTypeChecker()); + if (imports.length > 0) { + insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); + } + importAdder.writeFixes(changes, getQuotePreference(originalFile, preferences)); + changes.replaceRangeWithText(targetFile, pastedRange, pastedText); + host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); + } + else { + const context: CodeFixContextBase = { + sourceFile: updatedTargetFile.updatedFile, + program: updatedTargetFile.originalProgram, + cancellationToken: cancellationToken, + host: host, + preferences: preferences, + formatContext: formatContext + } + const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); + forEachChild(updatedTargetFile.updatedFile, function cb(node) { + if (isIdentifier(node)) { + if (!updatedTargetFile.updatedProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ true) && + !updatedTargetFile.originalProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ false)) { + //generate imports + importAdder.addImportsForUnknownSymbols(context, node, /*useAutoImportProvider*/ true); + } + } + else { + node.forEachChild(cb); + } + }); + changes.replaceRangeWithText(targetFile, pastedRange, pastedText); + importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); + host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); } - importAdder.writeFixes(changes, getQuotePreference(originalFile, preferences)); - changes.insertNodesAtEndOfFile(targetFile, statements, true); //NEEDS TO BE FIXED!!!!!!!!!!!! } -function getTargetFileImportsForKnownOriginalFile( +function getImportsFromKnownOriginalFile( originalFile: SourceFile, targetFile: SourceFile, program: Program, @@ -111,7 +96,7 @@ function getTargetFileImportsForKnownOriginalFile( importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker), isValidTypeOnlyUseSite); } catch { - for (const oldStatement of originalFile.statements) { //might be changed to just statements, meaning that the updated statements in the target file + for (const oldStatement of originalFile.statements) { forEachImportInStatement(oldStatement, i => { append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); }); @@ -153,79 +138,4 @@ function getTargetFileImportsForKnownOriginalFile( }); return append(copiedOldImports, makeImportOrRequire(targetFile, oldFileDefault, oldFileNamedImports, originalFile.fileName, program, host, useEsModuleSyntax, quotePreference)) -} -// interface FixInfo { -// readonly fix: ImportFix; -// readonly symbolName: string; -// readonly errorIdentifierText: string | undefined; -// readonly isJsxNamespaceFix?: boolean; -// } -// export function tempFunction(updatedFile: SourceFile, originalProgram: Program, node: Identifier, languageServiceHost: LanguageServiceHost, cancellationToken: CancellationToken, preferences: UserPreferences) { -// return flatMap(getSymbolNamesToImport(updatedFile, originalProgram.getTypeChecker(), node, originalProgram.getCompilerOptions()), symbolName => { -// // "default" is a keyword and not a legal identifier for the import, but appears as an identifier. -// if (symbolName === InternalSymbolName.Default) { -// return undefined; -// } -// const isValidTypeOnlyUseSite = isValidTypeOnlyAliasUseSite(node); -// const useRequire = shouldUseRequire(updatedFile, originalProgram); -// const exportInfo = getExportInfos(symbolName, isJSXTagName(node), getMeaningFromLocation(node), cancellationToken, updatedFile, originalProgram, true, languageServiceHost, preferences); -// //const t1 = exportInfo.values(); -// //const fix = ts.flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(updatedFile), isValidTypeOnlyUseSite, useRequire, originalProgram, updatedFile, languageServiceHost, preferences).fixes); -// return arrayFrom( -// flatMapIterator(exportInfo.values(), exportInfos => getImportFixes(exportInfos, node.getStart(updatedFile), isValidTypeOnlyUseSite, useRequire, originalProgram, updatedFile, languageServiceHost, preferences).fixes), -// fix => ({ fix, symbolName, errorIdentifierText: node.text, isJsxNamespaceFix: symbolName !== node.text }), -// ); -// }); - -// } - -// type ImportFix = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport | FixPromoteTypeOnlyImport; -// type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; - -const enum ImportFixKind { - UseNamespace, - JsdocTypeImport, - AddToExisting, - AddNew, - PromoteTypeOnly, -} -interface ImportFixBase { - readonly isReExport?: boolean; - readonly exportInfo?: SymbolExportInfo; - readonly moduleSpecifier: string; -} -const enum AddAsTypeOnly { - Allowed = 1 << 0, - Required = 1 << 1, - NotAllowed = 1 << 2, -} -interface FixPromoteTypeOnlyImport { - readonly kind: ImportFixKind.PromoteTypeOnly; - readonly typeOnlyAliasDeclaration: TypeOnlyAliasDeclaration; -} -interface Qualification { - readonly usagePosition: number; - readonly namespacePrefix: string; -} -interface FixUseNamespaceImport extends ImportFixBase, Qualification { - readonly kind: ImportFixKind.UseNamespace; -} -// interface FixAddJsdocTypeImport extends ImportFixBase { -// readonly kind: ImportFixKind.JsdocTypeImport; -// readonly usagePosition: number; -// readonly isReExport: boolean; -// readonly exportInfo: SymbolExportInfo; -// } -interface FixAddToExistingImport extends ImportFixBase { - readonly kind: ImportFixKind.AddToExisting; - readonly importClauseOrBindingPattern: ImportClause | ObjectBindingPattern; - readonly importKind: ImportKind.Default | ImportKind.Named; - readonly addAsTypeOnly: AddAsTypeOnly; -} -interface FixAddNewImport extends ImportFixBase { - readonly kind: ImportFixKind.AddNew; - readonly importKind: ImportKind; - readonly addAsTypeOnly: AddAsTypeOnly; - readonly useRequire: boolean; - readonly qualification?: Qualification; } \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index f3581f6a1a0ad..f622a742989d5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2099,10 +2099,10 @@ export function createLanguageService( formatOptions: FormatCodeSettings, originalFile?: string, copyLocation?: CopyRange - ): PostPasteImportFixes[]{ + ): PostPasteImportFixes{ synchronizeHostData(); const originalSourceFile = originalFile ? getValidSourceFile(originalFile) : undefined; - const edits = postPasteImportFixes.postPastImportFixProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host), originalSourceFile, copyLocation); + const edits = postPasteImportFixes.postPastImportFixProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host),cancellationToken, originalSourceFile, copyLocation); return edits; } diff --git a/src/services/types.ts b/src/services/types.ts index 60f7f53076a3b..73c915a1fccb8 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -433,10 +433,8 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; /** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; - /** @internal */ getFakeSourceFile(rootFile: string, formatContext: FormatContext, updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: Program | undefined): FixInfo[]; - /** @internal */ updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: Program | undefined}; - /** @internal */ revertUpdatedFile(rootFile: string, updatedText: string, originalText: string): void; -//needs to be changed to optional + /** @internal */ updateTargetFile?(rootFile: string, targetFileText: string, pastedText: string): { updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: Program | undefined }; + /** @internal */ revertUpdatedFile?(rootFile: string, updatedText: string, originalText: string): void; jsDocParsingMode?: JSDocParsingMode | undefined; } @@ -689,7 +687,7 @@ export interface LanguageService { getSupportedCodeFixes(fileName?: string): readonly string[]; dispose(): void; - getPostPasteImportFixes (targetFile: string, pastes: Array<{text: string; range: TextRange}>, preferences: UserPreferences, formatOptions: FormatCodeSettings, originalFile: string | undefined, copyLocation: CopyRange | undefined): PostPasteImportFixes[]; + getPostPasteImportFixes (targetFile: string, pastes: Array<{text: string; range: TextRange}>, preferences: UserPreferences, formatOptions: FormatCodeSettings, originalFile: string | undefined, copyLocation: CopyRange | undefined): PostPasteImportFixes; } export interface CopyRange { @@ -721,7 +719,7 @@ export interface PostPasteImportFixes { // targetFile: string, // targetFileText: string, // pastes: Array<{text: string; range: TextSpan}> - changes: FileTextChanges[]; + edits: readonly FileTextChanges[]; } export interface OrganizeImportsArgs extends CombinedCodeFixScope { diff --git a/tests/cases/fourslash/importNameCodeFix_add_all_missing_imports.ts b/tests/cases/fourslash/importNameCodeFix_add_all_missing_imports.ts index 524a4979f1bc7..0386beb369950 100644 --- a/tests/cases/fourslash/importNameCodeFix_add_all_missing_imports.ts +++ b/tests/cases/fourslash/importNameCodeFix_add_all_missing_imports.ts @@ -2,15 +2,19 @@ // @Filename: /a.ts ////export const a: number; - +////export const k: number; // @Filename: /b.ts ////export const b: number; // @Filename: /c.ts ////export const c: number; +// @Filename: /d.ts +////export const k: number; + // @Filename: /main.ts ////a; +////k; ////b; ////c; @@ -19,11 +23,12 @@ verify.codeFixAll({ fixId: "fixMissingImport", fixAllDescription: "Add all missing imports", newFileContent: -`import { a } from "./a"; +`import { a, k } from "./a"; import { b } from "./b"; import { c } from "./c"; a; +k; b; c;`, }); diff --git a/tests/cases/fourslash/server/postPasteImportFix2.ts b/tests/cases/fourslash/server/postPasteImportFix2.ts deleted file mode 100644 index e5385136e07de..0000000000000 --- a/tests/cases/fourslash/server/postPasteImportFix2.ts +++ /dev/null @@ -1,38 +0,0 @@ -/// - -// @Filename: file1.ts -//// export interface Test1 {} -//// export interface Test2 {} -//// export interface Test3 {} -//// export interface Test4 {} - -// @Filename: file2.ts -//// import { Test1, Test2, Test3, Test4 } from './file1'; -//// interface Testing { -//// test1: Test1; -//// test2: Test2; -//// test3: Test3; -//// test4: Test4; -//// } - -// @Filename: file3.ts -//// /*a*/const a = 10;/*b*/ - -// @Filename: tsconfig.json -////{ "files": ["file1.ts", "file2.ts", "file3.ts"] } - -goTo.select("a", "b"); -verify.postPasteImportFix({ - targetFile: "file3.ts", - pastes: [{ - text: `const a = 10; - interface Testing { - test1: Test1; - test2: Test2; - test3: Test3; - test4: Test4; - }`, - range: { pos: 13, end: 54 }, - }], - originalFile: "file2.ts", -}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix3.ts b/tests/cases/fourslash/server/postPasteImportFix_knownSourceFile.ts similarity index 69% rename from tests/cases/fourslash/server/postPasteImportFix3.ts rename to tests/cases/fourslash/server/postPasteImportFix_knownSourceFile.ts index c51259a35b45a..3e7c621ba2a54 100644 --- a/tests/cases/fourslash/server/postPasteImportFix3.ts +++ b/tests/cases/fourslash/server/postPasteImportFix_knownSourceFile.ts @@ -9,23 +9,22 @@ ////const c = a + b; ////const t = 9; -// @Filename: /file3.ts +// @Filename: /target.ts //// /*a*/export const tt = 2;/*b*/ //// function f(); +//// const p = 1; // @Filename: /tsconfig.json -////{ "files": ["file1.ts", "file2.ts", "file3.ts"] } +////{ "files": ["file1.ts", "file2.ts", "target.ts"] } goTo.select("a", "b"); format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFix({ - targetFile: "file3.ts", + targetFile: "target.ts", pastes: [{ - text: `export const tt = 2; - const c = a + b; - const t = 9; - function f();`, - range: { pos: 20, end: 22 }, + text: `const c = a + b; +const t = 9;`, + range: { pos: 21, end: 34 }, }], originalFile: "file2.ts", copyRange: { start: { line : 2, offset: 0}, end : { line: 3, offset: 0}}, @@ -36,16 +35,14 @@ export const a = 1; const c = a + b; const t = 9;`, - "/file3.ts": + "/target.ts": `import { a } from "./file2"; import { b } from './file1'; export const tt = 2; -function f(); const c = a + b; const t = 9; - -`, +const p = 1;`, } }); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts new file mode 100644 index 0000000000000..2b449267be050 --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts @@ -0,0 +1,46 @@ +/// + +// @Filename: /file1.ts +//// export const p = 10; +//// export const q = 12; + +// @Filename: /file3.ts +//// export const r = 10; +//// export const s = 12; + +// @Filename: /file2.ts +//// /*a*/const a = 1; +//// /*b*/const b = 2; +//// const c = 3; +//// const d = 4; + +// @Filename: /tsconfig.json +////{ "files": ["file1.ts", "file2.ts", "file3.ts"] } + +goTo.select("a", "b"); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFix({ + targetFile: "file2.ts", + pastes: [{ + text: `const g = p + q;\n`, + range: { pos: 13, end: 26 }, + }, + { + text: `function e(); +const f = r + s;`, + range: { pos: 39, end: 51 }, + + }], + newFileContents: { + "/file2.ts": +`import { p, q } from "./file1"; + +import { r, s } from "./file3"; + +const a = 1; +const g = p + q; +const c = 3; +function e(); +const f = r + s;` + } +}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts new file mode 100644 index 0000000000000..df8927fa64c5a --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts @@ -0,0 +1,50 @@ +/// + +// @Filename: /file1.ts +//// import { aa, bb } from "./other"; +//// export const r = 10; +//// export const s = 12; +//// export const t = aa + bb + r + s; +//// const u = 1; + +// @Filename: /target.ts +//// /*a*/const a = 1; +//// /*b*/const b = 2; +//// const c = 3; +//// const d = 4; + +// @Filename: /other.ts +//// export const aa = 1; +//// export const bb = 2; + +// @Filename: /tsconfig.json +////{ "files": ["file1.ts", "target.ts", "other.ts"] } + +goTo.select("a", "b"); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFix({ + targetFile: "target.ts", + pastes: [{ + text: `export const t = aa + bb + r + s;\n +const u = 1;`, + range: { pos: 13, end: 26 }, + }, + { + text: `export const t = aa + bb + r + s;\n +const u = 1;`, + range: { pos: 39, end: 51 }, + + }], + newFileContents: { + "/target.ts": +`import { r, s } from "./file1"; +import { aa, bb } from "./other"; + +const a = 1; +export const t = aa + bb + r + s; +const c = 3; +const u = 1;` + }, + originalFile: "file1.ts", + copyRange: { start: { line : 3, offset: 0}, end : { line: 4, offset: 12}}, +}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix1.ts b/tests/cases/fourslash/server/postPasteImportFix_unknownSourceFile.ts similarity index 64% rename from tests/cases/fourslash/server/postPasteImportFix1.ts rename to tests/cases/fourslash/server/postPasteImportFix_unknownSourceFile.ts index 9f86b05928142..74181e4a5c1eb 100644 --- a/tests/cases/fourslash/server/postPasteImportFix1.ts +++ b/tests/cases/fourslash/server/postPasteImportFix_unknownSourceFile.ts @@ -7,7 +7,9 @@ //// export interface Test4 {} // @Filename: /file2.ts -//// /*a*/const a = 10;/*b*/ +//// /*a*/const a = 10; +//// /*b*/const b = 10; +//// const c = 10; // @Filename: /tsconfig.json ////{ "files": ["file1.ts", "file2.ts"] } @@ -17,25 +19,25 @@ format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFix({ targetFile: "file2.ts", pastes: [{ - text: `const a = 10; - interface Testing { + text: `interface Testing { test1: Test1; test2: Test2; test3: Test3; test4: Test4; }`, - range: { pos: 0, end: 12 }, + range: { pos: 14, end: 27 }, }], newFileContents: { "/file2.ts": -`import { Test1, Test2, Test3, Test4 } from './file1' +`import { Test1, Test2, Test3, Test4 } from "./file1"; const a = 10; interface Testing { - test1: Test1; - test2: Test2; - test3: Test3; - test4: Test4; -}` + test1: Test1; + test2: Test2; + test3: Test3; + test4: Test4; + } +const c = 10;` } }); \ No newline at end of file From 64da77e12f285a345134d1c800e75ee94a51a83d Mon Sep 17 00:00:00 2001 From: navya9singh Date: Thu, 1 Feb 2024 11:27:00 -0800 Subject: [PATCH 04/18] working changes --- src/server/session.ts | 11 - src/services/postPasteImportFix.ts | 16 +- .../postPasteImportFix_knownSourceFile.js | 347 +++++++++++++++++ .../postPasteImportFix_multiplePastes1.js | 327 ++++++++++++++++ .../postPasteImportFix_multiplePastes2.js | 356 ++++++++++++++++++ .../postPasteImportFix_unknownSourceFile.js | 292 ++++++++++++++ .../postPasteImportFix_multiplePastes1.ts | 16 +- .../postPasteImportFix_multiplePastes2.ts | 14 +- 8 files changed, 1351 insertions(+), 28 deletions(-) create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_knownSourceFile.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes1.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes2.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_unknownSourceFile.js diff --git a/src/server/session.ts b/src/server/session.ts index 62fe53833ad75..189a9c9761e86 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2799,22 +2799,11 @@ export class Session implements EventSender { private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction | undefined { const { file, project } = this.getFileAndProject(args); - //const pastes: Array<{text: string; range: TextRange}> = arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange(paste.range, project.getScriptInfoForNormalizedPath(file)!)})); - //const textRange = this.getRange(args.pastes[0].range, project.getScriptInfoForNormalizedPath(file)!); const result = project.getLanguageService().getPostPasteImportFixes(args.targetFile, arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange(paste.range, project.getScriptInfoForNormalizedPath(file)!)})), this.getPreferences(file), this.getFormatOptions(file), args.originalFile, args.copyRange); - // const seenFiles = new Set(); - // const textChanges: FileTextChanges[] = []; - // for (const textChange of projectTextChanges) { - // if (!seenFiles.has(textChange.fileName)) { - // textChanges.push(textChange); - // } - // } if (result === undefined) { return undefined; } - //const allResults = result.map(postPasteAction => this.mapPostPasteAction(postPasteAction)); const allResults = this.mapPostPasteAction(result); - return allResults; } diff --git a/src/services/postPasteImportFix.ts b/src/services/postPasteImportFix.ts index 7c0340d1ea715..46afbf1dcb9a8 100644 --- a/src/services/postPasteImportFix.ts +++ b/src/services/postPasteImportFix.ts @@ -17,16 +17,15 @@ export function postPastImportFixProvider( copyLocation?: CopyRange): PostPasteImportFixes { let changes: FileTextChanges[] = []; - changes = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => pastes.forEach(({text, range}) => - { postPasteFixes(targetFile, host, text, range, preferences, formatContext, cancellationToken, changeTracker, originalFile, copyLocation)})); + changes = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => postPasteFixes(targetFile, host, pastes, preferences, formatContext, cancellationToken, changeTracker, originalFile, copyLocation)); + return { edits: changes }; } function postPasteFixes ( targetFile: SourceFile, host: LanguageServiceHost, - pastedText: string, - pastedRange: TextRange, + pastes: Array<{text: string; range: TextRange}>, preferences: UserPreferences, formatContext: formatting.FormatContext, cancellationToken: CancellationToken, @@ -34,7 +33,7 @@ function postPasteFixes ( originalFile?: SourceFile, copyLocation?: CopyRange) { - const updatedTargetFile = host.updateTargetFile?.(targetFile.fileName, targetFile.getText(), targetFile.getText().slice(0, pastedRange.pos) + pastedText + targetFile.getText().slice(0, pastedRange.end)); + const updatedTargetFile = host.updateTargetFile?.(targetFile.fileName, targetFile.getText(), targetFile.getText().slice(0, pastes[0].range.pos) + pastes[0].text + targetFile.getText().slice(0, pastes[0].range.end)); let statements: Statement[] = []; Debug.assert(updatedTargetFile && updatedTargetFile.updatedFile && updatedTargetFile.originalProgram && updatedTargetFile.updatedProgram); @@ -48,7 +47,7 @@ function postPasteFixes ( insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); } importAdder.writeFixes(changes, getQuotePreference(originalFile, preferences)); - changes.replaceRangeWithText(targetFile, pastedRange, pastedText); + //changes.replaceRangeWithText(targetFile, pastedRange, pastedText); host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); } else { @@ -73,10 +72,13 @@ function postPasteFixes ( node.forEachChild(cb); } }); - changes.replaceRangeWithText(targetFile, pastedRange, pastedText); + //changes.replaceRangeWithText(targetFile, pastedRange, pastedText); importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); } + pastes.forEach(({ text, range}) => { + changes.replaceRangeWithText(targetFile, range, text); + }); } function getImportsFromKnownOriginalFile( diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_knownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_knownSourceFile.js new file mode 100644 index 0000000000000..23d494bd3ac86 --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_knownSourceFile.js @@ -0,0 +1,347 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/file1.ts] +export const b = 2; + +//// [/file2.ts] +import { b } from './file1'; +const a = 1; +const c = a + b; +const t = 9; + +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/target.ts] +export const tt = 2; +function f(); +const p = 1; + +//// [/tsconfig.json] +{ "files": ["file1.ts", "file2.ts", "target.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/file1.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /file1.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/file1.ts", + "/file2.ts", + "/target.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /target.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export const b = 2;" + /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" + /target.ts Text-1 "export const tt = 2;\nfunction f();\nconst p = 1;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + file1.ts + Part of 'files' list in tsconfig.json + Imported via './file1' from file 'file2.ts' + file2.ts + Part of 'files' list in tsconfig.json + target.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/file1.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file2.ts: *new* + {"pollingInterval":500} +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/target.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "file": "/target.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /target.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file2.ts: + {"pollingInterval":500} +/lib.d.ts: + {"pollingInterval":500} +/lib.decorators.d.ts: + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: + {"pollingInterval":500} +/tsconfig.json: + {"pollingInterval":2000} + +watchedFiles *deleted*:: +/target.ts: + {"pollingInterval":500} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 2, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 3, + "type": "request", + "arguments": { + "file": "/target.ts", + "startLine": 2, + "startOffset": 1, + "endLine": 2, + "endOffset": 14, + "targetFile": "/target.ts", + "pastes": [ + { + "text": "const c = a + b;\nconst t = 9;", + "range": { + "file": "/target.ts", + "startLine": 2, + "startOffset": 1, + "endLine": 2, + "endOffset": 14 + } + } + ], + "originalFile": "file2.ts", + "copyRange": { + "start": { + "line": 2, + "offset": 0 + }, + "end": { + "line": 3, + "offset": 0 + } + } + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export const b = 2;" + /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" + /target.ts SVC-2-1 "export const tt = 2;\nconst c = a + b;\nconst t = 9;export const tt = 2;\nfunction f();;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results +Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export const b = 2;" + /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" + /target.ts SVC-2-2 "export const tt = 2;\nfunction f();\nconst p = 1;;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 3, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/file2.ts", + "textChanges": [ + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 1 + }, + "newText": "export " + } + ] + }, + { + "fileName": "/target.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { a } from \"./file2\";\n\n" + }, + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { b } from './file1';\n\n" + }, + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 14 + }, + "newText": "const c = a + b;\nconst t = 9;" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes1.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes1.js new file mode 100644 index 0000000000000..5cbb6a734470d --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes1.js @@ -0,0 +1,327 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/file1.ts] +export const p = 10; +export const q = 12; + +//// [/file2.ts] +const a = 1; +const b = 2; +const c = 3; +const d = 4; + +//// [/file3.ts] +export const r = 10; +export const s = 12; + +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/tsconfig.json] +{ "files": ["file1.ts", "file2.ts", "file3.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/file1.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /file1.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/file1.ts", + "/file2.ts", + "/file3.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file3.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export const p = 10;\nexport const q = 12;" + /file2.ts Text-1 "const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;" + /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + file1.ts + Part of 'files' list in tsconfig.json + file2.ts + Part of 'files' list in tsconfig.json + file3.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/file1.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file2.ts: *new* + {"pollingInterval":500} +/file3.ts: *new* + {"pollingInterval":500} +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "file": "/file2.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /file2.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +Info seq [hh:mm:ss:mss] FileName: /file2.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file3.ts: + {"pollingInterval":500} +/lib.d.ts: + {"pollingInterval":500} +/lib.decorators.d.ts: + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: + {"pollingInterval":500} +/tsconfig.json: + {"pollingInterval":2000} + +watchedFiles *deleted*:: +/file2.ts: + {"pollingInterval":500} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 2, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 3, + "type": "request", + "arguments": { + "file": "/file2.ts", + "startLine": 2, + "startOffset": 1, + "endLine": 3, + "endOffset": 1, + "targetFile": "/file2.ts", + "pastes": [ + { + "text": "const g = p + q;\nfunction e();\nconst f = r + s;\n", + "range": { + "file": "/file2.ts", + "startLine": 2, + "startOffset": 1, + "endLine": 3, + "endOffset": 1 + } + }, + { + "text": "const g = p + q;\nfunction e();\nconst f = r + s;\n", + "range": { + "file": "/file2.ts", + "startLine": 4, + "startOffset": 1, + "endLine": 4, + "endOffset": 13 + } + } + ] + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export const p = 10;\nexport const q = 12;" + /file2.ts SVC-2-1 "const a = 1;\nconst g = p + q;\nfunction e();\nconst f = r + s;\nconst a = 1;\nconst b = 2;\n;" + /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export const p = 10;\nexport const q = 12;" + /file2.ts SVC-2-2 "const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;;" + /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 3, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/file2.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { p, q } from \"./file1\";\nimport { r, s } from \"./file3\";\n\n" + }, + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 3, + "offset": 1 + }, + "newText": "const g = p + q;\nfunction e();\nconst f = r + s;\n" + }, + { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 13 + }, + "newText": "const g = p + q;\nfunction e();\nconst f = r + s;\n" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes2.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes2.js new file mode 100644 index 0000000000000..52bad6f959f07 --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes2.js @@ -0,0 +1,356 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/file1.ts] +import { aa, bb } from "./other"; +export const r = 10; +export const s = 12; +export const t = aa + bb + r + s; +const u = 1; + +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/other.ts] +export const aa = 1; +export const bb = 2; + +//// [/target.ts] +const a = 1; +const b = 2; +const c = 3; +const d = 4; + +//// [/tsconfig.json] +{ "files": ["file1.ts", "target.ts", "other.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/file1.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /file1.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/file1.ts", + "/target.ts", + "/other.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /target.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" + /file1.ts SVC-1-0 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" + /target.ts Text-1 "const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + other.ts + Imported via "./other" from file 'file1.ts' + Part of 'files' list in tsconfig.json + file1.ts + Part of 'files' list in tsconfig.json + target.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/file1.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/other.ts: *new* + {"pollingInterval":500} +/target.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "file": "/target.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /target.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/lib.d.ts: + {"pollingInterval":500} +/lib.decorators.d.ts: + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: + {"pollingInterval":500} +/other.ts: + {"pollingInterval":500} +/tsconfig.json: + {"pollingInterval":2000} + +watchedFiles *deleted*:: +/target.ts: + {"pollingInterval":500} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 2, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 3, + "type": "request", + "arguments": { + "file": "/target.ts", + "startLine": 2, + "startOffset": 1, + "endLine": 3, + "endOffset": 1, + "targetFile": "/target.ts", + "pastes": [ + { + "text": "export const t = aa + bb + r + s;\nconst u = 1;\n", + "range": { + "file": "/target.ts", + "startLine": 2, + "startOffset": 1, + "endLine": 3, + "endOffset": 1 + } + }, + { + "text": "export const t = aa + bb + r + s;\nconst u = 1;\n", + "range": { + "file": "/target.ts", + "startLine": 4, + "startOffset": 1, + "endLine": 4, + "endOffset": 13 + } + } + ], + "originalFile": "file1.ts", + "copyRange": { + "start": { + "line": 3, + "offset": 0 + }, + "end": { + "line": 4, + "offset": 12 + } + } + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" + /file1.ts SVC-1-0 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" + /target.ts SVC-2-1 "const a = 1;\nexport const t = aa + bb + r + s;\nconst u = 1;\nconst a = 1;\nconst b = 2;\n;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results +Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms +Info seq [hh:mm:ss:mss] getExportInfoMap: cache hit +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" + /file1.ts SVC-1-0 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" + /target.ts SVC-2-2 "const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 3, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/target.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { r, s } from \"./file1\";\n\n" + }, + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { aa, bb } from \"./other\";\n\n" + }, + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 3, + "offset": 1 + }, + "newText": "export const t = aa + bb + r + s;\nconst u = 1;\n" + }, + { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 13 + }, + "newText": "export const t = aa + bb + r + s;\nconst u = 1;\n" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_unknownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_unknownSourceFile.js new file mode 100644 index 0000000000000..3e21b762917c8 --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_unknownSourceFile.js @@ -0,0 +1,292 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/file1.ts] +export interface Test1 {} +export interface Test2 {} +export interface Test3 {} +export interface Test4 {} + +//// [/file2.ts] +const a = 10; +const b = 10; +const c = 10; + +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/tsconfig.json] +{ "files": ["file1.ts", "file2.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/file1.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /file1.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/file1.ts", + "/file2.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" + /file2.ts Text-1 "const a = 10;\nconst b = 10;\nconst c = 10;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + file1.ts + Part of 'files' list in tsconfig.json + file2.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/file1.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file2.ts: *new* + {"pollingInterval":500} +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "file": "/file2.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /file2.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +Info seq [hh:mm:ss:mss] FileName: /file2.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/lib.d.ts: + {"pollingInterval":500} +/lib.decorators.d.ts: + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: + {"pollingInterval":500} +/tsconfig.json: + {"pollingInterval":2000} + +watchedFiles *deleted*:: +/file2.ts: + {"pollingInterval":500} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 2, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 3, + "type": "request", + "arguments": { + "file": "/file2.ts", + "startLine": 2, + "startOffset": 1, + "endLine": 2, + "endOffset": 14, + "targetFile": "/file2.ts", + "pastes": [ + { + "text": "interface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }", + "range": { + "file": "/file2.ts", + "startLine": 2, + "startOffset": 1, + "endLine": 2, + "endOffset": 14 + } + } + ] + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" + /file2.ts SVC-2-1 "const a = 10;\ninterface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }const a = 10;\nconst b = 10;;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts SVC-1-0 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" + /file2.ts SVC-2-2 "const a = 10;\nconst b = 10;\nconst c = 10;;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 3, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/file2.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { Test1, Test2, Test3, Test4 } from \"./file1\";\n\n" + }, + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 14 + }, + "newText": "interface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts index 2b449267be050..acf943cf272c0 100644 --- a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts +++ b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts @@ -22,25 +22,31 @@ format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFix({ targetFile: "file2.ts", pastes: [{ - text: `const g = p + q;\n`, + text: `const g = p + q; +function e(); +const f = r + s;\n`, range: { pos: 13, end: 26 }, }, { - text: `function e(); -const f = r + s;`, + text: `const g = p + q; +function e(); +const f = r + s;\n`, range: { pos: 39, end: 51 }, }], newFileContents: { "/file2.ts": `import { p, q } from "./file1"; - import { r, s } from "./file3"; const a = 1; const g = p + q; +function e(); +const f = r + s; const c = 3; +const g = p + q; function e(); -const f = r + s;` +const f = r + s; +` } }); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts index df8927fa64c5a..d0e28c1452139 100644 --- a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts +++ b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts @@ -25,25 +25,29 @@ format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFix({ targetFile: "target.ts", pastes: [{ - text: `export const t = aa + bb + r + s;\n -const u = 1;`, + text: `export const t = aa + bb + r + s; +const u = 1;\n`, range: { pos: 13, end: 26 }, }, { - text: `export const t = aa + bb + r + s;\n -const u = 1;`, + text: `export const t = aa + bb + r + s; +const u = 1;\n`, range: { pos: 39, end: 51 }, }], newFileContents: { "/target.ts": `import { r, s } from "./file1"; + import { aa, bb } from "./other"; const a = 1; export const t = aa + bb + r + s; +const u = 1; const c = 3; -const u = 1;` +export const t = aa + bb + r + s; +const u = 1; +` }, originalFile: "file1.ts", copyRange: { start: { line : 3, offset: 0}, end : { line: 4, offset: 12}}, From 4fe48f622c75624954921718171afd121ad63d32 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Thu, 1 Feb 2024 11:40:20 -0800 Subject: [PATCH 05/18] removing extra code --- src/server/project.ts | 59 +-------------------------- src/services/codefixes/importFixes.ts | 8 ++-- src/services/types.ts | 3 -- 3 files changed, 5 insertions(+), 65 deletions(-) diff --git a/src/server/project.ts b/src/server/project.ts index 0056f6fb6e2d2..7796a7d2b859d 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1,6 +1,6 @@ import { info } from "console"; import { FormatContext } from "../services/_namespaces/ts.formatting"; -import { FixInfo, ImportFixWithModuleSpecifier, getFixesInfoForNonUMDImport, sortFixInfo } from "../services/codefixes/importFixes"; +import { FixInfo, ImportFixWithModuleSpecifier, sortFixInfo } from "../services/codefixes/importFixes"; import * as ts from "./_namespaces/ts"; import { addRange, @@ -315,63 +315,6 @@ const enum TypingWatcherType { type TypingWatchers = Map & { isInvoked?: boolean; }; -//========================= -//type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; -const enum ImportFixKind { - UseNamespace, - JsdocTypeImport, - AddToExisting, - AddNew, - PromoteTypeOnly, -} -const enum AddAsTypeOnly { - Allowed = 1 << 0, - Required = 1 << 1, - NotAllowed = 1 << 2, -} -// interface FixInfo { -// readonly fix: ImportFix; -// readonly symbolName: string; -// readonly errorIdentifierText: string | undefined; -// readonly isJsxNamespaceFix?: boolean; -// } -type ImportFix = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport | FixPromoteTypeOnlyImport; -interface ImportFixBase { - readonly isReExport?: boolean; - readonly exportInfo?: SymbolExportInfo; - readonly moduleSpecifier: string; -} -interface Qualification { - readonly usagePosition: number; - readonly namespacePrefix: string; -} -interface FixUseNamespaceImport extends ImportFixBase, Qualification { - readonly kind: ImportFixKind.UseNamespace; -} -interface FixAddJsdocTypeImport extends ImportFixBase { - readonly kind: ImportFixKind.JsdocTypeImport; - readonly usagePosition: number; - readonly isReExport: boolean; - readonly exportInfo: SymbolExportInfo; -} -interface FixAddToExistingImport extends ImportFixBase { - readonly kind: ImportFixKind.AddToExisting; - readonly importClauseOrBindingPattern: ImportClause | ts.ObjectBindingPattern; - readonly importKind: ts.ImportKind.Default | ts.ImportKind.Named; - readonly addAsTypeOnly: AddAsTypeOnly; -} -interface FixAddNewImport extends ImportFixBase { - readonly kind: ImportFixKind.AddNew; - readonly importKind: ts.ImportKind; - readonly addAsTypeOnly: AddAsTypeOnly; - readonly useRequire: boolean; - readonly qualification?: Qualification; -} -interface FixPromoteTypeOnlyImport { - readonly kind: ImportFixKind.PromoteTypeOnly; - readonly typeOnlyAliasDeclaration: ts.TypeOnlyAliasDeclaration; -} -//========================= export abstract class Project implements LanguageServiceHost, ModuleResolutionHost { private rootFiles: ScriptInfo[] = []; private rootFilesMap = new Map(); diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index a3b63d5239114..66a4896e0f97b 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -1183,7 +1183,7 @@ function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOp } } -export function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { +function getFixesInfoForNonUMDImport({ sourceFile, program, cancellationToken, host, preferences }: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] | undefined { const checker = program.getTypeChecker(); const compilerOptions = program.getCompilerOptions(); return flatMap(getSymbolNamesToImport(sourceFile, checker, symbolToken, compilerOptions), symbolName => { @@ -1212,7 +1212,7 @@ function getTypeOnlyPromotionFix(sourceFile: SourceFile, symbolToken: Identifier return { kind: ImportFixKind.PromoteTypeOnly, typeOnlyAliasDeclaration }; } -export function getSymbolNamesToImport(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier, compilerOptions: CompilerOptions): string[] { +function getSymbolNamesToImport(sourceFile: SourceFile, checker: TypeChecker, symbolToken: Identifier, compilerOptions: CompilerOptions): string[] { const parent = symbolToken.parent; if ((isJsxOpeningLikeElement(parent) || isJsxClosingElement(parent)) && parent.tagName === symbolToken && jsxModeNeedsExplicitImport(compilerOptions.jsx)) { const jsxNamespace = checker.getJsxNamespace(sourceFile); @@ -1231,7 +1231,7 @@ function needsJsxNamespaceFix(jsxNamespace: string, symbolToken: Identifier, che } // Returns a map from an exported symbol's ID to a list of every way it's (re-)exported. -export function getExportInfos( +function getExportInfos( symbolName: string, isJsxTagName: boolean, currentTokenMeaning: SemanticMeaning, @@ -1323,7 +1323,7 @@ function codeActionForFix( }); return createCodeFixAction(importFixName, changes, diag, importFixId, Diagnostics.Add_all_missing_imports); } -export function codeActionForFixWorker( +function codeActionForFixWorker( changes: textChanges.ChangeTracker, sourceFile: SourceFile, symbolName: string, diff --git a/src/services/types.ts b/src/services/types.ts index 73c915a1fccb8..1857a820aca9a 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -716,9 +716,6 @@ export const enum OrganizeImportsMode { } export interface PostPasteImportFixes { - // targetFile: string, - // targetFileText: string, - // pastes: Array<{text: string; range: TextSpan}> edits: readonly FileTextChanges[]; } From 17ff23ab0bd7d3bab2fcdd6decfdc934e8a6d23d Mon Sep 17 00:00:00 2001 From: navya9singh Date: Fri, 9 Feb 2024 13:18:50 -0800 Subject: [PATCH 06/18] Fixing protocol changes and tests --- src/harness/client.ts | 18 +- src/harness/fourslashImpl.ts | 5 +- src/harness/fourslashInterfaceImpl.ts | 15 +- src/server/project.ts | 6 +- src/server/protocol.ts | 14 +- src/server/session.ts | 3 +- .../_namespaces/ts.postPasteImportFixes.ts | 2 +- src/services/postPasteImportFixes.ts | 138 ++++++++ src/services/refactors/moveToFile.ts | 3 +- src/services/services.ts | 12 +- src/services/types.ts | 12 +- src/testRunner/tests.ts | 1 + .../tsserver/postPasteImportFixes.ts | 46 +++ .../postPasteImportFixes_existingImports1.js | 279 +++++++++++++++ .../postPasteImportFixes_existingImports2.js | 320 ++++++++++++++++++ .../postPasteImportFixes_knownSourceFile.js | 307 +++++++++++++++++ .../postPasteImportFixes_multiplePastes1.js | 292 ++++++++++++++++ .../postPasteImportFixes_multiplePastes2.js | 320 ++++++++++++++++++ .../postPasteImportFixes_pasteComments.js | 228 +++++++++++++ .../postPasteImportFixes_unknownSourceFile.js | 254 ++++++++++++++ tests/cases/fourslash/fourslash.ts | 12 +- .../postPasteImportFixes_existingImports1.ts | 38 +++ .../postPasteImportFixes_existingImports2.ts | 46 +++ .../postPasteImportFixes_knownSourceFile.ts | 46 +++ .../postPasteImportFixes_multiplePastes1.ts | 54 +++ .../postPasteImportFixes_multiplePastes2.ts | 53 +++ .../postPasteImportFixes_pasteComments.ts | 34 ++ .../postPasteImportFixes_unknownSourceFile.ts | 42 +++ 28 files changed, 2545 insertions(+), 55 deletions(-) create mode 100644 src/services/postPasteImportFixes.ts create mode 100644 src/testRunner/unittests/tsserver/postPasteImportFixes.ts create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js create mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js create mode 100644 tests/cases/fourslash/server/postPasteImportFixes_existingImports1.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFixes_existingImports2.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFixes_knownSourceFile.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFixes_multiplePastes1.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFixes_multiplePastes2.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFixes_pasteComments.ts create mode 100644 tests/cases/fourslash/server/postPasteImportFixes_unknownSourceFile.ts diff --git a/src/harness/client.ts b/src/harness/client.ts index b5fc806d76ce0..ae166c06ed207 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -14,7 +14,6 @@ import { computeLineAndCharacterOfPosition, computeLineStarts, computePositionOfLineAndCharacter, - CopyRange, createQueue, createTextSpanFromBounds, Debug, @@ -1012,13 +1011,18 @@ export class SessionClient implements LanguageService { return getSupportedCodeFixes(); } - getPostPasteImportFixes(targetFile: string, pastes: Array<{text: string; range: TextRange}>, _preferences: UserPreferences, _formatOptions: FormatCodeSettings, originalFile?: string, copyRange?: CopyRange): PostPasteImportFixes{ - const args = this.createFileLocationOrRangeRequestArgs(pastes[0].range, targetFile) as protocol.GetPostPasteImportFixesRequestArgs; - args.targetFile = targetFile; - args.pastes = arrayFrom(pastes.map(paste => ({text: paste.text, range: this.createFileRangeRequestArgs(targetFile, paste.range.pos, paste.range.end)}))); - args.originalFile = originalFile; - args.copyRange = copyRange; + getPostPasteImportFixes( + targetFile: string, + pastes: Array<{ text: string; range: TextRange }>, + _preferences: UserPreferences, + _formatOptions: FormatCodeSettings, + copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number } }): PostPasteImportFixes { + const args: protocol.GetPostPasteImportFixesRequestArgs = { + file: targetFile, + pastes: arrayFrom(pastes.map(paste => ({text: paste.text, range: { start: this.positionToOneBasedLineOffset(targetFile, paste.range.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.range.end)}}))), + copySpan: copySpan + } const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); const response = this.processResponse(request); if (!response.body) { diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index fd72eee8e840f..7bfa915f924e2 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -10,6 +10,7 @@ import { } from "./tsserverLogger"; import ArrayOrSingle = FourSlashInterface.ArrayOrSingle; +import { arrayFrom } from "./_namespaces/ts"; export const enum FourSlashTestType { Native, @@ -3562,8 +3563,8 @@ export class TestState { assert.deepEqual(actualModuleSpecifiers, moduleSpecifiers); } - public verifyPostPasteImportFixes(options: FourSlashInterface.PostPasteImportFixOptions): void{ - const editInfo = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, options.pastes, options.preferences, this.formatCodeSettings, options.originalFile, options.copyRange); + public verifyPostPasteImportFixes(options: FourSlashInterface.PostPasteImportFixOptions): void { + const editInfo = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, options.pastes, options.preferences, this.formatCodeSettings, options.copySpan); this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits); } diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 26c8d4b6ef61b..72fa4a5e047ea 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1,3 +1,4 @@ +import { Location } from "../server/protocol"; import * as FourSlash from "./_namespaces/FourSlash"; import * as ts from "./_namespaces/ts"; @@ -621,7 +622,7 @@ export class Verify extends VerifyNegatable { this.state.verifyOrganizeImports(newContent, mode, preferences); } - public postPasteImportFix(options: PostPasteImportFixOptions): void { + public postPasteImportFixes(options: PostPasteImportFixOptions): void { this.state.verifyPostPasteImportFixes(options); } } @@ -1883,12 +1884,11 @@ export interface VerifyCodeFixAllOptions { preferences?: ts.UserPreferences; } -export interface verifyPostPasteImportFix { +export interface VerifyPostPasteImportFix { targetFile: string; pastes: Array<{text: string; range: ts.TextRange}>; preferences: ts.UserPreferences; - originalFile?: string; - copyRange?: ts.CopyRange + copySpan?: { file: string, start: Location, end: Location } } export interface VerifyRefactorOptions { @@ -1933,10 +1933,9 @@ export interface MoveToFileOptions { export interface PostPasteImportFixOptions { readonly newFileContents: { readonly [fileName: string]: string; }; - readonly pastes: Array<{text: string; range: ts.TextRange}>,//{ pos, end }: ts.TextRange - readonly preferences: ts.UserPreferences, - readonly originalFile?: string, - readonly copyRange?: ts.CopyRange + readonly pastes: Array<{text: string; range: ts.TextRange}>; + readonly preferences: ts.UserPreferences; + readonly copySpan?: { file: string, start: Location, end: Location }; } export type RenameLocationsOptions = readonly RenameLocationOptions[] | { diff --git a/src/server/project.ts b/src/server/project.ts index 7796a7d2b859d..35d12cec6071f 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2219,16 +2219,16 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): {updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: ts.Program | undefined} { + updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): { updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: ts.Program | undefined } { const originalProgram = this.program; - this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length-1, pastedText); + this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length, pastedText); this.updateGraph(); return { updatedFile: (this.program?.getSourceFile(rootFile)), updatedProgram: this.program, originalProgram }; } /** @internal */ revertUpdatedFile(rootFile: string, updatedText: string, originalText: string) { - this.getScriptInfo(rootFile)?.editContent(0, updatedText.length-1, originalText); + this.getScriptInfo(rootFile)?.editContent(0, updatedText.length, originalText); this.updateGraph(); } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index f7b2bb85d36ca..9ea16d803c8e4 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -639,16 +639,10 @@ export interface GetPostPasteImportFixesRequest extends Request { command: CommandTypes.GetPostPasteImportFixes; arguments: GetPostPasteImportFixesRequestArgs; } -export type DocumentRange = FileRangeRequestArgs; -export type CopyRange = { - start: Location; - end: Location; -} -export type GetPostPasteImportFixesRequestArgs = FileLocationOrRangeRequestArgs & { - targetFile: string, - pastes: Array<{text: string; range: DocumentRange}>, - originalFile?: string, - copyRange?: CopyRange + +export type GetPostPasteImportFixesRequestArgs = FileRequestArgs & { + pastes: Array<{ text: string; range: TextSpan }>, + copySpan?: FileSpan, } export interface GetPostPasteImportFixesResponse extends Response { body: PostPasteImportAction; diff --git a/src/server/session.ts b/src/server/session.ts index 189a9c9761e86..a14467fd0345e 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2799,7 +2799,8 @@ export class Session implements EventSender { private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction | undefined { const { file, project } = this.getFileAndProject(args); - const result = project.getLanguageService().getPostPasteImportFixes(args.targetFile, arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange(paste.range, project.getScriptInfoForNormalizedPath(file)!)})), this.getPreferences(file), this.getFormatOptions(file), args.originalFile, args.copyRange); + const pastes = arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange({file: file, startLine: paste.range.start.line, startOffset: paste.range.start.offset, endLine: paste.range.end.line, endOffset: paste.range.end.offset}, project.getScriptInfoForNormalizedPath(file)!)})) + const result = project.getLanguageService().getPostPasteImportFixes( file, pastes, this.getPreferences(file), this.getFormatOptions(file), args.copySpan); if (result === undefined) { return undefined; } diff --git a/src/services/_namespaces/ts.postPasteImportFixes.ts b/src/services/_namespaces/ts.postPasteImportFixes.ts index c46fc22994e95..b75b8ec1d96cc 100644 --- a/src/services/_namespaces/ts.postPasteImportFixes.ts +++ b/src/services/_namespaces/ts.postPasteImportFixes.ts @@ -1 +1 @@ -export * from "../postPasteImportFix"; \ No newline at end of file +export * from "../postPasteImportFixes"; \ No newline at end of file diff --git a/src/services/postPasteImportFixes.ts b/src/services/postPasteImportFixes.ts new file mode 100644 index 0000000000000..611e564e74b4f --- /dev/null +++ b/src/services/postPasteImportFixes.ts @@ -0,0 +1,138 @@ +import { addRange, append } from "../compiler/core"; +import { SourceFile, Statement, UserPreferences, TypeChecker, AnyImportOrRequireStatement, Identifier, ModifierFlags, Program, TextRange, CancellationToken, ImportClause, ObjectBindingPattern, TypeOnlyAliasDeclaration, SymbolFlags } from "../compiler/types"; +import { hasSyntacticModifier, skipAlias } from "../compiler/utilities"; +import { codefix, Debug, factory, fileShouldUseJavaScriptRequire, forEachChild, formatting, getQuotePreference, ImportKind, insertImports, nodeSeenTracker, Symbol, SymbolExportInfo, textChanges, isIdentifier } from "./_namespaces/ts"; +import { addExportToChanges, filterImport, forEachImportInStatement, getExistingLocals, getTopLevelDeclarationStatement, getUsageInfo, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./refactors/moveToFile"; +import { CodeFixContextBase, FileTextChanges, LanguageServiceHost, PostPasteImportFixes } from "./types"; + +/** @internal */ +export function postPasteImportFixesProvider( + targetFile: SourceFile, + host: LanguageServiceHost, + pastes: Array<{ text: string; range: TextRange }>, + preferences: UserPreferences, + formatContext: formatting.FormatContext, + cancellationToken: CancellationToken, + originalFile?: SourceFile, + copyLocation?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }}): PostPasteImportFixes { + + const changes: FileTextChanges[] = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => postPasteFixes(targetFile, host, pastes, preferences, formatContext, cancellationToken, changeTracker, originalFile, copyLocation)); + + return { edits: changes }; +} + +function postPasteFixes ( + targetFile: SourceFile, + host: LanguageServiceHost, + pastes: Array<{ text: string; range: TextRange }>, + preferences: UserPreferences, + formatContext: formatting.FormatContext, + cancellationToken: CancellationToken, + changes: textChanges.ChangeTracker, + originalFile?: SourceFile, + copyLocation?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }}) { + const updatedTargetFile = host.updateTargetFile?.(targetFile.fileName, targetFile.getText(), targetFile.getText().slice(0, pastes[0].range.pos) + pastes[0].text + targetFile.getText().slice(pastes[0].range.end)); + let statements: Statement[] = []; + Debug.assert(updatedTargetFile && updatedTargetFile.updatedFile && updatedTargetFile.originalProgram && updatedTargetFile.updatedProgram); + + if (originalFile) { + addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation ? copyLocation.end.line + 1 : undefined); + const usage = getUsageInfo(originalFile, statements, updatedTargetFile.originalProgram.getTypeChecker(), getExistingLocals(updatedTargetFile.updatedFile, statements, updatedTargetFile.originalProgram.getTypeChecker())); + const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); + + const imports = getImportsFromKnownOriginalFile(originalFile, targetFile, updatedTargetFile.updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, preferences, host, updatedTargetFile.originalProgram.getTypeChecker()); + if (imports.length > 0) { + insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); + } + importAdder.writeFixes(changes, getQuotePreference(originalFile, preferences)); + host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); + } + else { + const context: CodeFixContextBase = { + sourceFile: updatedTargetFile.updatedFile, + program: updatedTargetFile.originalProgram, + cancellationToken: cancellationToken, + host: host, + preferences: preferences, + formatContext: formatContext + } + const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); + forEachChild(updatedTargetFile.updatedFile, function cb(node) { + if (isIdentifier(node)) { + if (!updatedTargetFile.originalProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ false)) { + //generate imports + importAdder.addImportsForUnknownSymbols(context, node, /*useAutoImportProvider*/ true); + } + } + else { + node.forEachChild(cb); + } + }); + importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); + host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); + } + pastes.forEach(({ text, range}) => { + range.pos === range.end ? changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text) : changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text); + }); +} + +function getImportsFromKnownOriginalFile( + originalFile: SourceFile, + targetFile: SourceFile, + program: Program, + importAdder: codefix.ImportAdder, + importsToCopy: Map, + targetFileImportsFromOldFile: Set, + changes: textChanges.ChangeTracker, + preferences: UserPreferences, + host: LanguageServiceHost, + checker: TypeChecker) { + const copiedOldImports: AnyImportOrRequireStatement[] = []; + importsToCopy.forEach((isValidTypeOnlyUseSite, symbol) => { + try { + importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker), isValidTypeOnlyUseSite); + } + catch { + for (const oldStatement of originalFile.statements) { + forEachImportInStatement(oldStatement, i => { + append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + }); + } + } + }); + + const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(targetFile.fileName, program, host, !!originalFile.commonJsModuleIndicator); + const quotePreference = getQuotePreference(targetFile, preferences); + // Also, import things used from the old file, and insert 'export' modifiers as necessary in the old file. + let oldFileDefault: Identifier | undefined; + const oldFileNamedImports: string[] = []; + const markSeenTop = nodeSeenTracker(); // Needed because multiple declarations may appear in `const x = 0, y = 1;`. + targetFileImportsFromOldFile.forEach(symbol => { + if (!symbol.declarations) { + return; + } + for (const decl of symbol.declarations) { + if (!isTopLevelDeclaration(decl)) continue; + const name = nameOfTopLevelDeclaration(decl); + if (!name) continue; + + const top = getTopLevelDeclarationStatement(decl); + if (markSeenTop(top)) { + addExportToChanges(originalFile, top, name, changes, useEsModuleSyntax); + } + if (importAdder && checker.isUnknownSymbol(symbol)) { + importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker)); + } + else { + if (hasSyntacticModifier(decl, ModifierFlags.Default)) { + oldFileDefault = name; + } + else { + oldFileNamedImports.push(name.text); + } + } + } + }); + + return append(copiedOldImports, makeImportOrRequire(targetFile, oldFileDefault, oldFileNamedImports, originalFile.fileName, program, host, useEsModuleSyntax, quotePreference)) +} \ No newline at end of file diff --git a/src/services/refactors/moveToFile.ts b/src/services/refactors/moveToFile.ts index 80064ab148951..c95163d4b71fd 100644 --- a/src/services/refactors/moveToFile.ts +++ b/src/services/refactors/moveToFile.ts @@ -1242,7 +1242,8 @@ function getOverloadRangeToMove(sourceFile: SourceFile, statement: Statement) { return undefined; } -function getExistingLocals(sourceFile: SourceFile, statements: readonly Statement[], checker: TypeChecker) { +/** @internal */ +export function getExistingLocals(sourceFile: SourceFile, statements: readonly Statement[], checker: TypeChecker) { const existingLocals = new Set(); for (const moduleSpecifier of sourceFile.imports) { const declaration = importFromModuleSpecifier(moduleSpecifier); diff --git a/src/services/services.ts b/src/services/services.ts index 1e4108a87a73c..aad974e869165 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -320,7 +320,6 @@ import { UserPreferences, VariableDeclaration, postPasteImportFixes, - CopyRange, PostPasteImportFixes, } from "./_namespaces/ts"; import * as NavigateTo from "./_namespaces/ts.NavigateTo"; @@ -2093,16 +2092,15 @@ export function createLanguageService( } function getPostPasteImportFixes ( - targetFile: string, - pastes: Array<{text: string; range: TextRange}>, + targetFile: string, + pastes: Array<{ text: string; range: TextRange }>, preferences: UserPreferences, formatOptions: FormatCodeSettings, - originalFile?: string, - copyLocation?: CopyRange + copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }} ): PostPasteImportFixes{ synchronizeHostData(); - const originalSourceFile = originalFile ? getValidSourceFile(originalFile) : undefined; - const edits = postPasteImportFixes.postPastImportFixProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host),cancellationToken, originalSourceFile, copyLocation); + const originalSourceFile = copySpan ? getValidSourceFile(copySpan.file) : undefined; + const edits = postPasteImportFixes.postPasteImportFixesProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host),cancellationToken, originalSourceFile, copySpan); return edits; } diff --git a/src/services/types.ts b/src/services/types.ts index 1857a820aca9a..94d7425445528 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -687,12 +687,12 @@ export interface LanguageService { getSupportedCodeFixes(fileName?: string): readonly string[]; dispose(): void; - getPostPasteImportFixes (targetFile: string, pastes: Array<{text: string; range: TextRange}>, preferences: UserPreferences, formatOptions: FormatCodeSettings, originalFile: string | undefined, copyLocation: CopyRange | undefined): PostPasteImportFixes; -} - -export interface CopyRange { - start: { line: number, offset: number }; - end: { line: number, offset: number } + getPostPasteImportFixes( + targetFile: string, + pastes: Array<{ text: string; range: TextRange }>, + preferences: UserPreferences, + formatOptions: FormatCodeSettings, + copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }}): PostPasteImportFixes; } export interface JsxClosingTagInfo { diff --git a/src/testRunner/tests.ts b/src/testRunner/tests.ts index 01d5ddea11d4d..a7fc40d26c7ff 100644 --- a/src/testRunner/tests.ts +++ b/src/testRunner/tests.ts @@ -214,3 +214,4 @@ import "./unittests/debugDeprecation"; import "./unittests/tsserver/inconsistentErrorInEditor"; import "./unittests/tsserver/getMoveToRefactoringFileSuggestions"; import "./unittests/skipJSDocParsing"; +import "./unittests/tsserver/postPasteImportFixes"; \ No newline at end of file diff --git a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts new file mode 100644 index 0000000000000..ecb55a5f84af6 --- /dev/null +++ b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts @@ -0,0 +1,46 @@ +import * as ts from "../../_namespaces/ts"; +import { + baselineTsserverLogs, + openFilesForSession, + TestSession, +} from "../helpers/tsserver"; +import { + createServerHost, + File, +} from "../helpers/virtualFileSystemWithWatch"; + +describe("unittests:: tsserver:: postPasteImportFixes", () => { + it("returns the same file unchanged, after updating and reverting changes added to a file", () => { + const target: File = { + path : "/project/a/target.ts", + content: `const a = 1; +const b = 2; +const c = 3;`, + } + const tsconfig: File = { + path: "/project/tsconfig.json", + content: "{}", + }; + const pastedText = `const a = 1; +function e(); +const f = r + s; +const b = 2; +const c = 3;`; + + const host = createServerHost([target, tsconfig]); + const session = new TestSession(host); + openFilesForSession([target], session); + + const originalContent = target.content; + const originalProgram = session.getProjectService().configuredProjects.get(tsconfig.path)!.getLanguageService().getProgram(); + + const hostProject = session.getProjectService().configuredProjects.get(tsconfig.path)!; + const updatedContent = hostProject.updateTargetFile(target.path, target.content, pastedText); + + if (updatedContent.updatedFile !== undefined) { + hostProject.revertUpdatedFile(target.path, updatedContent.updatedFile.getText(), originalContent); + } + assert.strictEqual(hostProject.getCurrentProgram()?.getSourceFileByPath(target.path as ts.Path)?.getText(), originalProgram?.getSourceFileByPath(target.path as ts.Path)?.getText()); + baselineTsserverLogs("getPostPasteImportFixes", "Returns the same file unchanged ", session); + }); +}); diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js new file mode 100644 index 0000000000000..8477babc0f4b3 --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js @@ -0,0 +1,279 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/other.ts] +export const t = 1; + +//// [/other2.ts] +export const t2 = 1; + +//// [/other3.ts] +export const t3 = 1; + +//// [/target.ts] +import { t } from "./other"; +import { t3 } from "./other3"; +const a = t + 1; +const b = 10; +const c = 10; + +//// [/tsconfig.json] +{ "files": ["target.ts", "other.ts", "other2.ts", "other3.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/target.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /target.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/target.ts", + "/other.ts", + "/other2.ts", + "/other3.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other2.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other3.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (7) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const t = 1;" + /other3.ts Text-1 "export const t3 = 1;" + /target.ts SVC-1-0 "import { t } from \"./other\";\nimport { t3 } from \"./other3\";\nconst a = t + 1;\nconst b = 10;\nconst c = 10;" + /other2.ts Text-1 "export const t2 = 1;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + other.ts + Imported via "./other" from file 'target.ts' + Part of 'files' list in tsconfig.json + other3.ts + Imported via "./other3" from file 'target.ts' + Part of 'files' list in tsconfig.json + target.ts + Part of 'files' list in tsconfig.json + other2.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/target.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (7) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/other.ts: *new* + {"pollingInterval":500} +/other2.ts: *new* + {"pollingInterval":500} +/other3.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 1, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "file": "/target.ts", + "pastes": [ + { + "text": "const m = t3 + t2 + 1;", + "range": { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 14 + } + } + } + ] + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (7) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const t = 1;" + /other3.ts Text-1 "export const t3 = 1;" + /target.ts SVC-1-1 "import { t } from \"./other\";\nimport { t3 } from \"./other3\";\nconst a = t + 1;\nconst m = t3 + t2 + 1;\nconst c = 10;" + /other2.ts Text-1 "export const t2 = 1;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (7) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const t = 1;" + /other3.ts Text-1 "export const t3 = 1;" + /target.ts SVC-1-2 "import { t } from \"./other\";\nimport { t3 } from \"./other3\";\nconst a = t + 1;\nconst b = 10;\nconst c = 10;" + /other2.ts Text-1 "export const t2 = 1;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 2, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/target.ts", + "textChanges": [ + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 1 + }, + "newText": "import { t2 } from \"./other2\";\n" + }, + { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 14 + }, + "newText": "const m = t3 + t2 + 1;" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js new file mode 100644 index 0000000000000..8b9854f9637de --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js @@ -0,0 +1,320 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/originalFile.ts] +import { t2 } from "./other2"; +import { t3 } from "./other3"; +export const n = 10; +export const m = t3 + t2 + n; + +//// [/other.ts] +export const t = 1; + +//// [/other2.ts] +export const t2 = 1; + +//// [/other3.ts] +export const t3 = 1; + +//// [/target.ts] +import { t } from "./other"; +import { t3 } from "./other3"; +const a = t + 1; +const b = 10; +const c = 10; + +//// [/tsconfig.json] +{ "files": ["target.ts", "originalFile.ts", "other.ts", "other2.ts", "other3.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/target.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /target.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/target.ts", + "/originalFile.ts", + "/other.ts", + "/other2.ts", + "/other3.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /originalFile.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other2.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other3.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (8) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const t = 1;" + /other3.ts Text-1 "export const t3 = 1;" + /target.ts SVC-1-0 "import { t } from \"./other\";\nimport { t3 } from \"./other3\";\nconst a = t + 1;\nconst b = 10;\nconst c = 10;" + /other2.ts Text-1 "export const t2 = 1;" + /originalFile.ts Text-1 "import { t2 } from \"./other2\";\nimport { t3 } from \"./other3\";\nexport const n = 10;\nexport const m = t3 + t2 + n;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + other.ts + Imported via "./other" from file 'target.ts' + Part of 'files' list in tsconfig.json + other3.ts + Imported via "./other3" from file 'target.ts' + Imported via "./other3" from file 'originalFile.ts' + Part of 'files' list in tsconfig.json + target.ts + Part of 'files' list in tsconfig.json + other2.ts + Imported via "./other2" from file 'originalFile.ts' + Part of 'files' list in tsconfig.json + originalFile.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/target.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (8) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/originalFile.ts: *new* + {"pollingInterval":500} +/other.ts: *new* + {"pollingInterval":500} +/other2.ts: *new* + {"pollingInterval":500} +/other3.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 1, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "file": "/target.ts", + "pastes": [ + { + "text": "const m = t3 + t2 + n;", + "range": { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 14 + } + } + } + ], + "copySpan": { + "file": "originalFile.ts", + "start": { + "line": 3, + "offset": 0 + }, + "end": { + "line": 3, + "offset": 30 + } + } + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (8) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const t = 1;" + /other3.ts Text-1 "export const t3 = 1;" + /target.ts SVC-1-1 "import { t } from \"./other\";\nimport { t3 } from \"./other3\";\nconst a = t + 1;\nconst m = t3 + t2 + n;\nconst c = 10;" + /other2.ts Text-1 "export const t2 = 1;" + /originalFile.ts Text-1 "import { t2 } from \"./other2\";\nimport { t3 } from \"./other3\";\nexport const n = 10;\nexport const m = t3 + t2 + n;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results +Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (8) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const t = 1;" + /other3.ts Text-1 "export const t3 = 1;" + /target.ts SVC-1-2 "import { t } from \"./other\";\nimport { t3 } from \"./other3\";\nconst a = t + 1;\nconst b = 10;\nconst c = 10;" + /other2.ts Text-1 "export const t2 = 1;" + /originalFile.ts Text-1 "import { t2 } from \"./other2\";\nimport { t3 } from \"./other3\";\nexport const n = 10;\nexport const m = t3 + t2 + n;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 2, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/target.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { n } from \"./originalFile\";\n" + }, + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 1 + }, + "newText": "import { t2 } from \"./other2\";\n" + }, + { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 14 + }, + "newText": "const m = t3 + t2 + n;" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js new file mode 100644 index 0000000000000..60fb7ede7b610 --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js @@ -0,0 +1,307 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/file1.ts] +export const b = 2; + +//// [/file2.ts] +import { b } from './file1'; +const a = 1; +const c = a + b; +const t = 9; + +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/target.ts] +export const tt = 2; +function f(); +const p = 1; + +//// [/tsconfig.json] +{ "files": ["file1.ts", "file2.ts", "target.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/target.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /target.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/file1.ts", + "/file2.ts", + "/target.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file1.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export const b = 2;" + /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" + /target.ts SVC-1-0 "export const tt = 2;\nfunction f();\nconst p = 1;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + file1.ts + Part of 'files' list in tsconfig.json + Imported via './file1' from file 'file2.ts' + file2.ts + Part of 'files' list in tsconfig.json + target.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/target.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file1.ts: *new* + {"pollingInterval":500} +/file2.ts: *new* + {"pollingInterval":500} +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 1, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "file": "/target.ts", + "pastes": [ + { + "text": "const c = a + b;\nconst t = 9;", + "range": { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 14 + } + } + } + ], + "copySpan": { + "file": "file2.ts", + "start": { + "line": 2, + "offset": 0 + }, + "end": { + "line": 3, + "offset": 0 + } + } + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export const b = 2;" + /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" + /target.ts SVC-1-1 "export const tt = 2;\nconst c = a + b;\nconst t = 9;\nconst p = 1;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results +Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export const b = 2;" + /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" + /target.ts SVC-1-2 "export const tt = 2;\nfunction f();\nconst p = 1;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 2, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/file2.ts", + "textChanges": [ + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 1 + }, + "newText": "export " + } + ] + }, + { + "fileName": "/target.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { a } from \"./file2\";\n\n" + }, + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { b } from './file1';\n\n" + }, + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 14 + }, + "newText": "const c = a + b;\nconst t = 9;" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js new file mode 100644 index 0000000000000..727d587a6636e --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js @@ -0,0 +1,292 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/file1.ts] +export const p = 10; +export const q = 12; + +//// [/file3.ts] +export const r = 10; +export const s = 12; + +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/target.ts] +const a = 1; + +const b = 2; +const c = 3; + +const d = 4; + +//// [/tsconfig.json] +{ "files": ["file1.ts", "target.ts", "file3.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/target.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /target.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/file1.ts", + "/target.ts", + "/file3.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file1.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file3.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export const p = 10;\nexport const q = 12;" + /target.ts SVC-1-0 "const a = 1;\n\nconst b = 2;\nconst c = 3;\n\nconst d = 4;" + /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + file1.ts + Part of 'files' list in tsconfig.json + target.ts + Part of 'files' list in tsconfig.json + file3.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/target.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file1.ts: *new* + {"pollingInterval":500} +/file3.ts: *new* + {"pollingInterval":500} +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 1, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "file": "/target.ts", + "pastes": [ + { + "text": "const g = p + q;\nfunction e();\nconst f = r + s;", + "range": { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 1 + } + } + }, + { + "text": "const g = p + q;\nfunction e();\nconst f = r + s;", + "range": { + "start": { + "line": 5, + "offset": 1 + }, + "end": { + "line": 5, + "offset": 1 + } + } + } + ] + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export const p = 10;\nexport const q = 12;" + /target.ts SVC-1-1 "const a = 1;\nconst g = p + q;\nfunction e();\nconst f = r + s;\nconst b = 2;\nconst c = 3;\n\nconst d = 4;" + /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export const p = 10;\nexport const q = 12;" + /target.ts SVC-1-2 "const a = 1;\n\nconst b = 2;\nconst c = 3;\n\nconst d = 4;" + /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 2, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/target.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { p, q } from \"./file1\";\nimport { r, s } from \"./file3\";\n\n" + }, + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 1 + }, + "newText": "const g = p + q;\nfunction e();\nconst f = r + s;" + }, + { + "start": { + "line": 5, + "offset": 1 + }, + "end": { + "line": 5, + "offset": 1 + }, + "newText": "const g = p + q;\nfunction e();\nconst f = r + s;" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js new file mode 100644 index 0000000000000..abd684c7c5130 --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js @@ -0,0 +1,320 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/file1.ts] +import { aa, bb } from "./other"; +export const r = 10; +export const s = 12; +export const t = aa + bb + r + s; +const u = 1; + +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/other.ts] +export const aa = 1; +export const bb = 2; + +//// [/target.ts] +const a = 1; +const b = 2; +const c = 3; + +const d = 4; + +//// [/tsconfig.json] +{ "files": ["file1.ts", "target.ts", "other.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/target.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /target.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/file1.ts", + "/target.ts", + "/other.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file1.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" + /file1.ts Text-1 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" + /target.ts SVC-1-0 "const a = 1;\nconst b = 2;\nconst c = 3;\n\nconst d = 4;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + other.ts + Imported via "./other" from file 'file1.ts' + Part of 'files' list in tsconfig.json + file1.ts + Part of 'files' list in tsconfig.json + target.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/target.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file1.ts: *new* + {"pollingInterval":500} +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/other.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 1, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "file": "/target.ts", + "pastes": [ + { + "text": "export const t = aa + bb + r + s;\nconst u = 1;", + "range": { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 13 + } + } + }, + { + "text": "export const t = aa + bb + r + s;\nconst u = 1;", + "range": { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 1 + } + } + } + ], + "copySpan": { + "file": "file1.ts", + "start": { + "line": 3, + "offset": 0 + }, + "end": { + "line": 4, + "offset": 12 + } + } + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" + /file1.ts Text-1 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" + /target.ts SVC-1-1 "const a = 1;\nexport const t = aa + bb + r + s;\nconst u = 1;\nconst c = 3;\n\nconst d = 4;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results +Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms +Info seq [hh:mm:ss:mss] getExportInfoMap: cache hit +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (6) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" + /file1.ts Text-1 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" + /target.ts SVC-1-2 "const a = 1;\nconst b = 2;\nconst c = 3;\n\nconst d = 4;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 2, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/target.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { r, s } from \"./file1\";\n\n" + }, + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { aa, bb } from \"./other\";\n\n" + }, + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 13 + }, + "newText": "export const t = aa + bb + r + s;\nconst u = 1;" + }, + { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 1 + }, + "newText": "export const t = aa + bb + r + s;\nconst u = 1;" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js new file mode 100644 index 0000000000000..c6cb16bb03451 --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js @@ -0,0 +1,228 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/target.ts] +const a = 10; +const b = 10; +const c = 10; + +//// [/tsconfig.json] +{ "files": ["target.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/target.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /target.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/target.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (4) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /target.ts SVC-1-0 "const a = 10;\nconst b = 10;\nconst c = 10;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + target.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/target.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (4) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 1, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "file": "/target.ts", + "pastes": [ + { + "text": "/**\n* Testing comment line 1\n* line 2\n* line 3\n* line 4\n*/", + "range": { + "start": { + "line": 2, + "offset": 14 + }, + "end": { + "line": 2, + "offset": 14 + } + } + } + ] + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (4) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /target.ts SVC-1-1 "const a = 10;\nconst b = 10;/**\n* Testing comment line 1\n* line 2\n* line 3\n* line 4\n*/\nconst c = 10;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (4) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /target.ts SVC-1-2 "const a = 10;\nconst b = 10;\nconst c = 10;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 2, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/target.ts", + "textChanges": [ + { + "start": { + "line": 2, + "offset": 14 + }, + "end": { + "line": 2, + "offset": 14 + }, + "newText": "/**\n* Testing comment line 1\n* line 2\n* line 3\n* line 4\n*/" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js new file mode 100644 index 0000000000000..ddc26b007de3e --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js @@ -0,0 +1,254 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/file1.ts] +export interface Test1 {} +export interface Test2 {} +export interface Test3 {} +export interface Test4 {} + +//// [/file2.ts] +const a = 10; +const b = 10; +const c = 10; + +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/tsconfig.json] +{ "files": ["file1.ts", "file2.ts"] } + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/file2.ts" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /file2.ts :: Config file name: /tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/tsconfig.json", + "reason": "Creating possible configured project for /file2.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { + "rootNames": [ + "/file1.ts", + "/file2.ts" + ], + "options": { + "configFilePath": "/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file1.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" + /file2.ts SVC-1-0 "const a = 10;\nconst b = 10;\nconst c = 10;" + + + lib.d.ts + Default library for target 'es5' + lib.decorators.d.ts + Library referenced via 'decorators' from file 'lib.d.ts' + lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file 'lib.d.ts' + file1.ts + Part of 'files' list in tsconfig.json + file2.ts + Part of 'files' list in tsconfig.json + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/file2.ts", + "configFile": "/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /file2.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /tsconfig.json +After Request +watchedFiles:: +/file1.ts: *new* + {"pollingInterval":500} +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/tsconfig.json: *new* + {"pollingInterval":2000} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "formatOptions": { + "indentSize": 4, + "tabSize": 4, + "newLineCharacter": "\n", + "convertTabsToSpaces": true, + "indentStyle": 2, + "insertSpaceAfterConstructor": false, + "insertSpaceAfterCommaDelimiter": true, + "insertSpaceAfterSemicolonInForStatements": true, + "insertSpaceBeforeAndAfterBinaryOperators": true, + "insertSpaceAfterKeywordsInControlFlowStatements": true, + "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, + "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, + "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, + "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, + "insertSpaceBeforeFunctionParenthesis": false, + "placeOpenBraceOnNewLineForFunctions": false, + "placeOpenBraceOnNewLineForControlBlocks": false, + "semicolons": "ignore", + "trimTrailingWhitespace": true, + "indentSwitchCase": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] Format host information updated +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 1, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "file": "/file2.ts", + "pastes": [ + { + "text": "interface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }", + "range": { + "start": { + "line": 3, + "offset": 1 + }, + "end": { + "line": 3, + "offset": 1 + } + } + } + ] + }, + "command": "getPostPasteImportFixes" + } +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" + /file2.ts SVC-1-1 "const a = 10;\nconst b = 10;\ninterface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }const c = 10;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (5) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /file1.ts Text-1 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" + /file2.ts SVC-1-2 "const a = 10;\nconst b = 10;\nconst c = 10;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "getPostPasteImportFixes", + "request_seq": 2, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + }, + "body": { + "edits": [ + { + "fileName": "/file2.ts", + "textChanges": [ + { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 1 + }, + "newText": "import { Test1, Test2, Test3, Test4 } from \"./file1\";\n\n" + }, + { + "start": { + "line": 3, + "offset": 1 + }, + "end": { + "line": 3, + "offset": 1 + }, + "newText": "interface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }" + } + ] + } + ] + } + } \ No newline at end of file diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index a4287e99ab189..e73659845bd61 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -216,10 +216,6 @@ declare namespace FourSlashInterface { line: number; offset: number; } - interface CopyRange { - start: Location; - end: Location; - } class test_ { markers(): Marker[]; markerNames(): string[]; @@ -452,12 +448,10 @@ declare namespace FourSlashInterface { toggleMultilineComment(newFileContent: string): void; commentSelection(newFileContent: string): void; uncommentSelection(newFileContent: string): void; - postPasteImportFix(options: { + postPasteImportFixes(options: { newFileContents: { readonly [fileName: string]: string }; - targetFile: string, - pastes: Array<{text: string; range: {pos: number, end: number}}> - originalFile?: string, - copyRange?: CopyRange, + pastes: Array<{ text: string; range: { pos: number, end: number }}>; + copySpan?: { file: string, start: Location, end: Location }, }): void; } class edit { diff --git a/tests/cases/fourslash/server/postPasteImportFixes_existingImports1.ts b/tests/cases/fourslash/server/postPasteImportFixes_existingImports1.ts new file mode 100644 index 0000000000000..82aeef5f7d998 --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFixes_existingImports1.ts @@ -0,0 +1,38 @@ +/// + +// @Filename: /target.ts +//// import { t } from "./other"; +//// import { t3 } from "./other3"; +//// const a = t + 1; +//// [|const b = 10;|] +//// const c = 10; + +// @Filename: /other.ts +//// export const t = 1; + +// @Filename: /other2.ts +//// export const t2 = 1; + +// @Filename: /other3.ts +//// export const t3 = 1; + +// @Filename: /tsconfig.json +////{ "files": ["target.ts", "other.ts", "other2.ts", "other3.ts"] } + +const range = test.ranges(); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFixes({ + pastes: [{ + text: `const m = t3 + t2 + 1;`, + range: range[0], + }], + newFileContents: { + "/target.ts": +`import { t } from "./other"; +import { t2 } from "./other2"; +import { t3 } from "./other3"; +const a = t + 1; +const m = t3 + t2 + 1; +const c = 10;` + } +}); diff --git a/tests/cases/fourslash/server/postPasteImportFixes_existingImports2.ts b/tests/cases/fourslash/server/postPasteImportFixes_existingImports2.ts new file mode 100644 index 0000000000000..3ad98da93f4cb --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFixes_existingImports2.ts @@ -0,0 +1,46 @@ +/// + +// @Filename: /target.ts +//// import { t } from "./other"; +//// import { t3 } from "./other3"; +//// const a = t + 1; +//// [|const b = 10;|] +//// const c = 10; + +// @Filename: /other.ts +//// export const t = 1; + +// @Filename: /other2.ts +//// export const t2 = 1; + +// @Filename: /other3.ts +//// export const t3 = 1; + +// @Filename: /originalFile.ts +//// import { t2 } from "./other2"; +//// import { t3 } from "./other3"; +//// export const n = 10; +//// export const m = t3 + t2 + n; + +// @Filename: /tsconfig.json +////{ "files": ["target.ts", "originalFile.ts", "other.ts", "other2.ts", "other3.ts"] } + +const range = test.ranges(); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFixes({ + pastes: [{ + text: `const m = t3 + t2 + n;`, + range: range[0], + }], + newFileContents: { + "/target.ts": +`import { n } from "./originalFile"; +import { t } from "./other"; +import { t2 } from "./other2"; +import { t3 } from "./other3"; +const a = t + 1; +const m = t3 + t2 + n; +const c = 10;` + }, + copySpan: { file: "originalFile.ts", start: { line : 3, offset: 0}, end : { line: 3, offset: 30}}, +}); diff --git a/tests/cases/fourslash/server/postPasteImportFixes_knownSourceFile.ts b/tests/cases/fourslash/server/postPasteImportFixes_knownSourceFile.ts new file mode 100644 index 0000000000000..97722efb4ea37 --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFixes_knownSourceFile.ts @@ -0,0 +1,46 @@ +/// + +// @Filename: /target.ts +//// export const tt = 2; +//// [|function f();|] +//// const p = 1; + +// @Filename: /file1.ts +////export const b = 2; + +// @Filename: /file2.ts +////import { b } from './file1'; +////const a = 1; +////const c = a + b; +////const t = 9; + +// @Filename: /tsconfig.json +////{ "files": ["file1.ts", "file2.ts", "target.ts"] } + +const range = test.ranges(); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFixes({ + pastes: [{ + text: `const c = a + b; +const t = 9;`, + range: range[0], + }], + copySpan: { file:"file2.ts", start: { line : 2, offset: 0}, end : { line: 3, offset: 0}}, + newFileContents: { + "/file2.ts": +`import { b } from './file1'; +export const a = 1; +const c = a + b; +const t = 9;`, + + "/target.ts": +`import { a } from "./file2"; + +import { b } from './file1'; + +export const tt = 2; +const c = a + b; +const t = 9; +const p = 1;`, + } +}); diff --git a/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes1.ts b/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes1.ts new file mode 100644 index 0000000000000..bef58f87b1899 --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes1.ts @@ -0,0 +1,54 @@ +/// + +// @Filename: /target.ts +//// const a = 1; +//// [||] +//// const b = 2; +//// const c = 3; +//// [||] +//// const d = 4; + +// @Filename: /file1.ts +//// export const p = 10; +//// export const q = 12; + +// @Filename: /file3.ts +//// export const r = 10; +//// export const s = 12; + +// @Filename: /tsconfig.json +////{ "files": ["file1.ts", "target.ts", "file3.ts"] } + +const range = test.ranges(); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFixes({ + pastes: [{ + text: `const g = p + q; +function e(); +const f = r + s;`, + range: range[0], + }, + { + text: `const g = p + q; +function e(); +const f = r + s;`, + range: range[1], + + }], + newFileContents: { + "/target.ts": +`import { p, q } from "./file1"; +import { r, s } from "./file3"; + +const a = 1; +const g = p + q; +function e(); +const f = r + s; +const b = 2; +const c = 3; +const g = p + q; +function e(); +const f = r + s; +const d = 4;` + } +}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes2.ts b/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes2.ts new file mode 100644 index 0000000000000..93ea4de93e5bf --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes2.ts @@ -0,0 +1,53 @@ +/// + +// @Filename: /target.ts +//// const a = 1; +//// [|const b = 2;|] +//// const c = 3; +//// [||] +//// const d = 4; + +// @Filename: /file1.ts +//// import { aa, bb } from "./other"; +//// export const r = 10; +//// export const s = 12; +//// export const t = aa + bb + r + s; +//// const u = 1; + +// @Filename: /other.ts +//// export const aa = 1; +//// export const bb = 2; + +// @Filename: /tsconfig.json +////{ "files": ["file1.ts", "target.ts", "other.ts"] } + +const range = test.ranges(); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFixes({ + pastes: [{ + text: `export const t = aa + bb + r + s; +const u = 1;`, + range: range[0], + }, + { + text: `export const t = aa + bb + r + s; +const u = 1;`, + range: range[1], + + }], + newFileContents: { + "/target.ts": +`import { r, s } from "./file1"; + +import { aa, bb } from "./other"; + +const a = 1; +export const t = aa + bb + r + s; +const u = 1; +const c = 3; +export const t = aa + bb + r + s; +const u = 1; +const d = 4;` + }, + copySpan: { file: "file1.ts", start: { line : 3, offset: 0}, end : { line: 4, offset: 12}}, +}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFixes_pasteComments.ts b/tests/cases/fourslash/server/postPasteImportFixes_pasteComments.ts new file mode 100644 index 0000000000000..60c272e5d9447 --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFixes_pasteComments.ts @@ -0,0 +1,34 @@ +/// + +// @Filename: /target.ts +//// const a = 10; +//// const b = 10;[||] +//// const c = 10; + +// @Filename: /tsconfig.json +////{ "files": ["target.ts"] } + +const range = test.ranges(); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFixes({ + pastes: [{ + text: `/** +* Testing comment line 1 +* line 2 +* line 3 +* line 4 +*/`, + range: range[0], + }], + newFileContents: { + "/target.ts": +`const a = 10; +const b = 10;/** +* Testing comment line 1 +* line 2 +* line 3 +* line 4 +*/ +const c = 10;` + } +}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFixes_unknownSourceFile.ts b/tests/cases/fourslash/server/postPasteImportFixes_unknownSourceFile.ts new file mode 100644 index 0000000000000..009d847fdca3c --- /dev/null +++ b/tests/cases/fourslash/server/postPasteImportFixes_unknownSourceFile.ts @@ -0,0 +1,42 @@ +/// + +// @Filename: /file2.ts +//// const a = 10; +//// const b = 10; +//// [||]const c = 10; + +// @Filename: /file1.ts +//// export interface Test1 {} +//// export interface Test2 {} +//// export interface Test3 {} +//// export interface Test4 {} + +// @Filename: /tsconfig.json +////{ "files": ["file1.ts", "file2.ts"] } + +const range = test.ranges(); +format.setOption("insertSpaceAfterSemicolonInForStatements", true); +verify.postPasteImportFixes({ + pastes: [{ + text: `interface Testing { + test1: Test1; + test2: Test2; + test3: Test3; + test4: Test4; + }`, + range: range[0], + }], + newFileContents: { + "/file2.ts": +`import { Test1, Test2, Test3, Test4 } from "./file1"; + +const a = 10; +const b = 10; +interface Testing { + test1: Test1; + test2: Test2; + test3: Test3; + test4: Test4; + }const c = 10;` + } +}); \ No newline at end of file From 1b89d2ee726496c8ba758b406c326aa08e38c0e1 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Fri, 9 Feb 2024 13:21:54 -0800 Subject: [PATCH 07/18] Removing deleted files --- src/services/postPasteImportFix.ts | 143 ------------------ .../postPasteImportFix_knownSourceFile.ts | 48 ------ .../postPasteImportFix_multiplePastes1.ts | 52 ------- .../postPasteImportFix_multiplePastes2.ts | 54 ------- .../postPasteImportFix_unknownSourceFile.ts | 43 ------ 5 files changed, 340 deletions(-) delete mode 100644 src/services/postPasteImportFix.ts delete mode 100644 tests/cases/fourslash/server/postPasteImportFix_knownSourceFile.ts delete mode 100644 tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts delete mode 100644 tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts delete mode 100644 tests/cases/fourslash/server/postPasteImportFix_unknownSourceFile.ts diff --git a/src/services/postPasteImportFix.ts b/src/services/postPasteImportFix.ts deleted file mode 100644 index 46afbf1dcb9a8..0000000000000 --- a/src/services/postPasteImportFix.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { addRange, append } from "../compiler/core"; -import { SourceFile, Statement, UserPreferences, TypeChecker, AnyImportOrRequireStatement, Identifier, ModifierFlags, Program, TextRange, CancellationToken, ImportClause, ObjectBindingPattern, TypeOnlyAliasDeclaration, SymbolFlags } from "../compiler/types"; -import { hasSyntacticModifier, skipAlias } from "../compiler/utilities"; -import { codefix, Debug, factory, fileShouldUseJavaScriptRequire, forEachChild, formatting, getQuotePreference, ImportKind, insertImports, nodeSeenTracker, Symbol, SymbolExportInfo, textChanges, isIdentifier } from "./_namespaces/ts"; -import { addExportToChanges, filterImport, forEachImportInStatement, getTopLevelDeclarationStatement, getUsageInfo, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./refactors/moveToFile"; -import { CodeFixContextBase, CopyRange, FileTextChanges, LanguageServiceHost, PostPasteImportFixes } from "./types"; - -/** @internal */ -export function postPastImportFixProvider( - targetFile: SourceFile, - host: LanguageServiceHost, - pastes: Array<{text: string; range: TextRange}>, - preferences: UserPreferences, - formatContext: formatting.FormatContext, - cancellationToken: CancellationToken, - originalFile?: SourceFile, - copyLocation?: CopyRange): PostPasteImportFixes { - - let changes: FileTextChanges[] = []; - changes = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => postPasteFixes(targetFile, host, pastes, preferences, formatContext, cancellationToken, changeTracker, originalFile, copyLocation)); - - return { edits: changes }; -} - -function postPasteFixes ( - targetFile: SourceFile, - host: LanguageServiceHost, - pastes: Array<{text: string; range: TextRange}>, - preferences: UserPreferences, - formatContext: formatting.FormatContext, - cancellationToken: CancellationToken, - changes: textChanges.ChangeTracker, - originalFile?: SourceFile, - copyLocation?: CopyRange) { - - const updatedTargetFile = host.updateTargetFile?.(targetFile.fileName, targetFile.getText(), targetFile.getText().slice(0, pastes[0].range.pos) + pastes[0].text + targetFile.getText().slice(0, pastes[0].range.end)); - let statements: Statement[] = []; - Debug.assert(updatedTargetFile && updatedTargetFile.updatedFile && updatedTargetFile.originalProgram && updatedTargetFile.updatedProgram); - - if (originalFile) { - addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation ? copyLocation.end.line + 1 : undefined); - const usage = getUsageInfo(originalFile, statements, updatedTargetFile.originalProgram.getTypeChecker()); - const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); - - const imports = getImportsFromKnownOriginalFile(originalFile, targetFile, updatedTargetFile.updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, preferences, host, updatedTargetFile.originalProgram.getTypeChecker()); - if (imports.length > 0) { - insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); - } - importAdder.writeFixes(changes, getQuotePreference(originalFile, preferences)); - //changes.replaceRangeWithText(targetFile, pastedRange, pastedText); - host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); - } - else { - const context: CodeFixContextBase = { - sourceFile: updatedTargetFile.updatedFile, - program: updatedTargetFile.originalProgram, - cancellationToken: cancellationToken, - host: host, - preferences: preferences, - formatContext: formatContext - } - const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); - forEachChild(updatedTargetFile.updatedFile, function cb(node) { - if (isIdentifier(node)) { - if (!updatedTargetFile.updatedProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ true) && - !updatedTargetFile.originalProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ false)) { - //generate imports - importAdder.addImportsForUnknownSymbols(context, node, /*useAutoImportProvider*/ true); - } - } - else { - node.forEachChild(cb); - } - }); - //changes.replaceRangeWithText(targetFile, pastedRange, pastedText); - importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); - host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); - } - pastes.forEach(({ text, range}) => { - changes.replaceRangeWithText(targetFile, range, text); - }); -} - -function getImportsFromKnownOriginalFile( - originalFile: SourceFile, - targetFile: SourceFile, - program: Program, - importAdder: codefix.ImportAdder, - importsToCopy: Map, - targetFileImportsFromOldFile: Set, - changes: textChanges.ChangeTracker, - preferences: UserPreferences, - host: LanguageServiceHost, - checker: TypeChecker) { - const copiedOldImports: AnyImportOrRequireStatement[] = []; - importsToCopy.forEach((isValidTypeOnlyUseSite, symbol) => { - try { - importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker), isValidTypeOnlyUseSite); - } - catch { - for (const oldStatement of originalFile.statements) { - forEachImportInStatement(oldStatement, i => { - append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); - }); - } - } - }); - - const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(targetFile.fileName, program, host, !!originalFile.commonJsModuleIndicator); - const quotePreference = getQuotePreference(targetFile, preferences); - // Also, import things used from the old file, and insert 'export' modifiers as necessary in the old file. - let oldFileDefault: Identifier | undefined; - const oldFileNamedImports: string[] = []; - const markSeenTop = nodeSeenTracker(); // Needed because multiple declarations may appear in `const x = 0, y = 1;`. - targetFileImportsFromOldFile.forEach(symbol => { - if (!symbol.declarations) { - return; - } - for (const decl of symbol.declarations) { - if (!isTopLevelDeclaration(decl)) continue; - const name = nameOfTopLevelDeclaration(decl); - if (!name) continue; - - const top = getTopLevelDeclarationStatement(decl); - if (markSeenTop(top)) { - addExportToChanges(originalFile, top, name, changes, useEsModuleSyntax); - } - if (importAdder && checker.isUnknownSymbol(symbol)) { - importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker)); - } - else { - if (hasSyntacticModifier(decl, ModifierFlags.Default)) { - oldFileDefault = name; - } - else { - oldFileNamedImports.push(name.text); - } - } - } - }); - - return append(copiedOldImports, makeImportOrRequire(targetFile, oldFileDefault, oldFileNamedImports, originalFile.fileName, program, host, useEsModuleSyntax, quotePreference)) -} \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix_knownSourceFile.ts b/tests/cases/fourslash/server/postPasteImportFix_knownSourceFile.ts deleted file mode 100644 index 3e7c621ba2a54..0000000000000 --- a/tests/cases/fourslash/server/postPasteImportFix_knownSourceFile.ts +++ /dev/null @@ -1,48 +0,0 @@ -/// - -// @Filename: /file1.ts -////export const b = 2; - -// @Filename: /file2.ts -////import { b } from './file1'; -////const a = 1; -////const c = a + b; -////const t = 9; - -// @Filename: /target.ts -//// /*a*/export const tt = 2;/*b*/ -//// function f(); -//// const p = 1; - -// @Filename: /tsconfig.json -////{ "files": ["file1.ts", "file2.ts", "target.ts"] } - -goTo.select("a", "b"); -format.setOption("insertSpaceAfterSemicolonInForStatements", true); -verify.postPasteImportFix({ - targetFile: "target.ts", - pastes: [{ - text: `const c = a + b; -const t = 9;`, - range: { pos: 21, end: 34 }, - }], - originalFile: "file2.ts", - copyRange: { start: { line : 2, offset: 0}, end : { line: 3, offset: 0}}, - newFileContents: { - "/file2.ts": -`import { b } from './file1'; -export const a = 1; -const c = a + b; -const t = 9;`, - - "/target.ts": -`import { a } from "./file2"; - -import { b } from './file1'; - -export const tt = 2; -const c = a + b; -const t = 9; -const p = 1;`, - } -}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts deleted file mode 100644 index acf943cf272c0..0000000000000 --- a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes1.ts +++ /dev/null @@ -1,52 +0,0 @@ -/// - -// @Filename: /file1.ts -//// export const p = 10; -//// export const q = 12; - -// @Filename: /file3.ts -//// export const r = 10; -//// export const s = 12; - -// @Filename: /file2.ts -//// /*a*/const a = 1; -//// /*b*/const b = 2; -//// const c = 3; -//// const d = 4; - -// @Filename: /tsconfig.json -////{ "files": ["file1.ts", "file2.ts", "file3.ts"] } - -goTo.select("a", "b"); -format.setOption("insertSpaceAfterSemicolonInForStatements", true); -verify.postPasteImportFix({ - targetFile: "file2.ts", - pastes: [{ - text: `const g = p + q; -function e(); -const f = r + s;\n`, - range: { pos: 13, end: 26 }, - }, - { - text: `const g = p + q; -function e(); -const f = r + s;\n`, - range: { pos: 39, end: 51 }, - - }], - newFileContents: { - "/file2.ts": -`import { p, q } from "./file1"; -import { r, s } from "./file3"; - -const a = 1; -const g = p + q; -function e(); -const f = r + s; -const c = 3; -const g = p + q; -function e(); -const f = r + s; -` - } -}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts b/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts deleted file mode 100644 index d0e28c1452139..0000000000000 --- a/tests/cases/fourslash/server/postPasteImportFix_multiplePastes2.ts +++ /dev/null @@ -1,54 +0,0 @@ -/// - -// @Filename: /file1.ts -//// import { aa, bb } from "./other"; -//// export const r = 10; -//// export const s = 12; -//// export const t = aa + bb + r + s; -//// const u = 1; - -// @Filename: /target.ts -//// /*a*/const a = 1; -//// /*b*/const b = 2; -//// const c = 3; -//// const d = 4; - -// @Filename: /other.ts -//// export const aa = 1; -//// export const bb = 2; - -// @Filename: /tsconfig.json -////{ "files": ["file1.ts", "target.ts", "other.ts"] } - -goTo.select("a", "b"); -format.setOption("insertSpaceAfterSemicolonInForStatements", true); -verify.postPasteImportFix({ - targetFile: "target.ts", - pastes: [{ - text: `export const t = aa + bb + r + s; -const u = 1;\n`, - range: { pos: 13, end: 26 }, - }, - { - text: `export const t = aa + bb + r + s; -const u = 1;\n`, - range: { pos: 39, end: 51 }, - - }], - newFileContents: { - "/target.ts": -`import { r, s } from "./file1"; - -import { aa, bb } from "./other"; - -const a = 1; -export const t = aa + bb + r + s; -const u = 1; -const c = 3; -export const t = aa + bb + r + s; -const u = 1; -` - }, - originalFile: "file1.ts", - copyRange: { start: { line : 3, offset: 0}, end : { line: 4, offset: 12}}, -}); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFix_unknownSourceFile.ts b/tests/cases/fourslash/server/postPasteImportFix_unknownSourceFile.ts deleted file mode 100644 index 74181e4a5c1eb..0000000000000 --- a/tests/cases/fourslash/server/postPasteImportFix_unknownSourceFile.ts +++ /dev/null @@ -1,43 +0,0 @@ -/// - -// @Filename: /file1.ts -//// export interface Test1 {} -//// export interface Test2 {} -//// export interface Test3 {} -//// export interface Test4 {} - -// @Filename: /file2.ts -//// /*a*/const a = 10; -//// /*b*/const b = 10; -//// const c = 10; - -// @Filename: /tsconfig.json -////{ "files": ["file1.ts", "file2.ts"] } - -goTo.select("a", "b"); -format.setOption("insertSpaceAfterSemicolonInForStatements", true); -verify.postPasteImportFix({ - targetFile: "file2.ts", - pastes: [{ - text: `interface Testing { - test1: Test1; - test2: Test2; - test3: Test3; - test4: Test4; - }`, - range: { pos: 14, end: 27 }, - }], - newFileContents: { - "/file2.ts": -`import { Test1, Test2, Test3, Test4 } from "./file1"; - -const a = 10; -interface Testing { - test1: Test1; - test2: Test2; - test3: Test3; - test4: Test4; - } -const c = 10;` - } -}); \ No newline at end of file From e6515ea51085e890cd6e3ee66e97698bdcaba09c Mon Sep 17 00:00:00 2001 From: navya9singh Date: Fri, 9 Feb 2024 13:25:39 -0800 Subject: [PATCH 08/18] Removing deleted files --- .../postPasteImportFix_knownSourceFile.js | 347 ----------------- .../postPasteImportFix_multiplePastes1.js | 327 ---------------- .../postPasteImportFix_multiplePastes2.js | 356 ------------------ .../postPasteImportFix_unknownSourceFile.js | 292 -------------- 4 files changed, 1322 deletions(-) delete mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_knownSourceFile.js delete mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes1.js delete mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes2.js delete mode 100644 tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_unknownSourceFile.js diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_knownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_knownSourceFile.js deleted file mode 100644 index 23d494bd3ac86..0000000000000 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_knownSourceFile.js +++ /dev/null @@ -1,347 +0,0 @@ -currentDirectory:: / useCaseSensitiveFileNames: false -Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist -//// [/file1.ts] -export const b = 2; - -//// [/file2.ts] -import { b } from './file1'; -const a = 1; -const c = a + b; -const t = 9; - -//// [/lib.d.ts] -lib.d.ts-Text - -//// [/lib.decorators.d.ts] -lib.decorators.d.ts-Text - -//// [/lib.decorators.legacy.d.ts] -lib.decorators.legacy.d.ts-Text - -//// [/target.ts] -export const tt = 2; -function f(); -const p = 1; - -//// [/tsconfig.json] -{ "files": ["file1.ts", "file2.ts", "target.ts"] } - - -Info seq [hh:mm:ss:mss] request: - { - "seq": 0, - "type": "request", - "arguments": { - "file": "/file1.ts" - }, - "command": "open" - } -Info seq [hh:mm:ss:mss] Search path: / -Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json -Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "projectLoadingStart", - "body": { - "projectName": "/tsconfig.json", - "reason": "Creating possible configured project for /file1.ts to open" - } - } -Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { - "rootNames": [ - "/file1.ts", - "/file2.ts", - "/target.ts" - ], - "options": { - "configFilePath": "/tsconfig.json" - } -} -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /target.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export const b = 2;" - /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" - /target.ts Text-1 "export const tt = 2;\nfunction f();\nconst p = 1;" - - - lib.d.ts - Default library for target 'es5' - lib.decorators.d.ts - Library referenced via 'decorators' from file 'lib.d.ts' - lib.decorators.legacy.d.ts - Library referenced via 'decorators.legacy' from file 'lib.d.ts' - file1.ts - Part of 'files' list in tsconfig.json - Imported via './file1' from file 'file2.ts' - file2.ts - Part of 'files' list in tsconfig.json - target.ts - Part of 'files' list in tsconfig.json - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "projectLoadingFinish", - "body": { - "projectName": "/tsconfig.json" - } - } -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "configFileDiag", - "body": { - "triggerFile": "/file1.ts", - "configFile": "/tsconfig.json", - "diagnostics": [] - } - } -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Open files: -Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -After Request -watchedFiles:: -/file2.ts: *new* - {"pollingInterval":500} -/lib.d.ts: *new* - {"pollingInterval":500} -/lib.decorators.d.ts: *new* - {"pollingInterval":500} -/lib.decorators.legacy.d.ts: *new* - {"pollingInterval":500} -/target.ts: *new* - {"pollingInterval":500} -/tsconfig.json: *new* - {"pollingInterval":2000} - -Info seq [hh:mm:ss:mss] request: - { - "seq": 1, - "type": "request", - "arguments": { - "file": "/target.ts" - }, - "command": "open" - } -Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /target.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Search path: / -Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Open files: -Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -After Request -watchedFiles:: -/file2.ts: - {"pollingInterval":500} -/lib.d.ts: - {"pollingInterval":500} -/lib.decorators.d.ts: - {"pollingInterval":500} -/lib.decorators.legacy.d.ts: - {"pollingInterval":500} -/tsconfig.json: - {"pollingInterval":2000} - -watchedFiles *deleted*:: -/target.ts: - {"pollingInterval":500} - -Info seq [hh:mm:ss:mss] request: - { - "seq": 2, - "type": "request", - "arguments": { - "formatOptions": { - "indentSize": 4, - "tabSize": 4, - "newLineCharacter": "\n", - "convertTabsToSpaces": true, - "indentStyle": 2, - "insertSpaceAfterConstructor": false, - "insertSpaceAfterCommaDelimiter": true, - "insertSpaceAfterSemicolonInForStatements": true, - "insertSpaceBeforeAndAfterBinaryOperators": true, - "insertSpaceAfterKeywordsInControlFlowStatements": true, - "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, - "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, - "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, - "insertSpaceBeforeFunctionParenthesis": false, - "placeOpenBraceOnNewLineForFunctions": false, - "placeOpenBraceOnNewLineForControlBlocks": false, - "semicolons": "ignore", - "trimTrailingWhitespace": true, - "indentSwitchCase": true - } - }, - "command": "configure" - } -Info seq [hh:mm:ss:mss] Format host information updated -Info seq [hh:mm:ss:mss] response: - { - "seq": 0, - "type": "response", - "command": "configure", - "request_seq": 2, - "success": true - } -Info seq [hh:mm:ss:mss] request: - { - "seq": 3, - "type": "request", - "arguments": { - "file": "/target.ts", - "startLine": 2, - "startOffset": 1, - "endLine": 2, - "endOffset": 14, - "targetFile": "/target.ts", - "pastes": [ - { - "text": "const c = a + b;\nconst t = 9;", - "range": { - "file": "/target.ts", - "startLine": 2, - "startOffset": 1, - "endLine": 2, - "endOffset": 14 - } - } - ], - "originalFile": "file2.ts", - "copyRange": { - "start": { - "line": 2, - "offset": 0 - }, - "end": { - "line": 3, - "offset": 0 - } - } - }, - "command": "getPostPasteImportFixes" - } -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export const b = 2;" - /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" - /target.ts SVC-2-1 "export const tt = 2;\nconst c = a + b;\nconst t = 9;export const tt = 2;\nfunction f();;" - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results -Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export const b = 2;" - /file2.ts Text-1 "import { b } from './file1';\nconst a = 1;\nconst c = a + b;\nconst t = 9;" - /target.ts SVC-2-2 "export const tt = 2;\nfunction f();\nconst p = 1;;" - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] response: - { - "seq": 0, - "type": "response", - "command": "getPostPasteImportFixes", - "request_seq": 3, - "success": true, - "performanceData": { - "updateGraphDurationMs": * - }, - "body": { - "edits": [ - { - "fileName": "/file2.ts", - "textChanges": [ - { - "start": { - "line": 2, - "offset": 1 - }, - "end": { - "line": 2, - "offset": 1 - }, - "newText": "export " - } - ] - }, - { - "fileName": "/target.ts", - "textChanges": [ - { - "start": { - "line": 1, - "offset": 1 - }, - "end": { - "line": 1, - "offset": 1 - }, - "newText": "import { a } from \"./file2\";\n\n" - }, - { - "start": { - "line": 1, - "offset": 1 - }, - "end": { - "line": 1, - "offset": 1 - }, - "newText": "import { b } from './file1';\n\n" - }, - { - "start": { - "line": 2, - "offset": 1 - }, - "end": { - "line": 2, - "offset": 14 - }, - "newText": "const c = a + b;\nconst t = 9;" - } - ] - } - ] - } - } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes1.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes1.js deleted file mode 100644 index 5cbb6a734470d..0000000000000 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes1.js +++ /dev/null @@ -1,327 +0,0 @@ -currentDirectory:: / useCaseSensitiveFileNames: false -Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist -//// [/file1.ts] -export const p = 10; -export const q = 12; - -//// [/file2.ts] -const a = 1; -const b = 2; -const c = 3; -const d = 4; - -//// [/file3.ts] -export const r = 10; -export const s = 12; - -//// [/lib.d.ts] -lib.d.ts-Text - -//// [/lib.decorators.d.ts] -lib.decorators.d.ts-Text - -//// [/lib.decorators.legacy.d.ts] -lib.decorators.legacy.d.ts-Text - -//// [/tsconfig.json] -{ "files": ["file1.ts", "file2.ts", "file3.ts"] } - - -Info seq [hh:mm:ss:mss] request: - { - "seq": 0, - "type": "request", - "arguments": { - "file": "/file1.ts" - }, - "command": "open" - } -Info seq [hh:mm:ss:mss] Search path: / -Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json -Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "projectLoadingStart", - "body": { - "projectName": "/tsconfig.json", - "reason": "Creating possible configured project for /file1.ts to open" - } - } -Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { - "rootNames": [ - "/file1.ts", - "/file2.ts", - "/file3.ts" - ], - "options": { - "configFilePath": "/tsconfig.json" - } -} -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file3.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export const p = 10;\nexport const q = 12;" - /file2.ts Text-1 "const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;" - /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" - - - lib.d.ts - Default library for target 'es5' - lib.decorators.d.ts - Library referenced via 'decorators' from file 'lib.d.ts' - lib.decorators.legacy.d.ts - Library referenced via 'decorators.legacy' from file 'lib.d.ts' - file1.ts - Part of 'files' list in tsconfig.json - file2.ts - Part of 'files' list in tsconfig.json - file3.ts - Part of 'files' list in tsconfig.json - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "projectLoadingFinish", - "body": { - "projectName": "/tsconfig.json" - } - } -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "configFileDiag", - "body": { - "triggerFile": "/file1.ts", - "configFile": "/tsconfig.json", - "diagnostics": [] - } - } -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Open files: -Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -After Request -watchedFiles:: -/file2.ts: *new* - {"pollingInterval":500} -/file3.ts: *new* - {"pollingInterval":500} -/lib.d.ts: *new* - {"pollingInterval":500} -/lib.decorators.d.ts: *new* - {"pollingInterval":500} -/lib.decorators.legacy.d.ts: *new* - {"pollingInterval":500} -/tsconfig.json: *new* - {"pollingInterval":2000} - -Info seq [hh:mm:ss:mss] request: - { - "seq": 1, - "type": "request", - "arguments": { - "file": "/file2.ts" - }, - "command": "open" - } -Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Search path: / -Info seq [hh:mm:ss:mss] For info: /file2.ts :: Config file name: /tsconfig.json -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Open files: -Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -Info seq [hh:mm:ss:mss] FileName: /file2.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -After Request -watchedFiles:: -/file3.ts: - {"pollingInterval":500} -/lib.d.ts: - {"pollingInterval":500} -/lib.decorators.d.ts: - {"pollingInterval":500} -/lib.decorators.legacy.d.ts: - {"pollingInterval":500} -/tsconfig.json: - {"pollingInterval":2000} - -watchedFiles *deleted*:: -/file2.ts: - {"pollingInterval":500} - -Info seq [hh:mm:ss:mss] request: - { - "seq": 2, - "type": "request", - "arguments": { - "formatOptions": { - "indentSize": 4, - "tabSize": 4, - "newLineCharacter": "\n", - "convertTabsToSpaces": true, - "indentStyle": 2, - "insertSpaceAfterConstructor": false, - "insertSpaceAfterCommaDelimiter": true, - "insertSpaceAfterSemicolonInForStatements": true, - "insertSpaceBeforeAndAfterBinaryOperators": true, - "insertSpaceAfterKeywordsInControlFlowStatements": true, - "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, - "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, - "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, - "insertSpaceBeforeFunctionParenthesis": false, - "placeOpenBraceOnNewLineForFunctions": false, - "placeOpenBraceOnNewLineForControlBlocks": false, - "semicolons": "ignore", - "trimTrailingWhitespace": true, - "indentSwitchCase": true - } - }, - "command": "configure" - } -Info seq [hh:mm:ss:mss] Format host information updated -Info seq [hh:mm:ss:mss] response: - { - "seq": 0, - "type": "response", - "command": "configure", - "request_seq": 2, - "success": true - } -Info seq [hh:mm:ss:mss] request: - { - "seq": 3, - "type": "request", - "arguments": { - "file": "/file2.ts", - "startLine": 2, - "startOffset": 1, - "endLine": 3, - "endOffset": 1, - "targetFile": "/file2.ts", - "pastes": [ - { - "text": "const g = p + q;\nfunction e();\nconst f = r + s;\n", - "range": { - "file": "/file2.ts", - "startLine": 2, - "startOffset": 1, - "endLine": 3, - "endOffset": 1 - } - }, - { - "text": "const g = p + q;\nfunction e();\nconst f = r + s;\n", - "range": { - "file": "/file2.ts", - "startLine": 4, - "startOffset": 1, - "endLine": 4, - "endOffset": 13 - } - } - ] - }, - "command": "getPostPasteImportFixes" - } -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export const p = 10;\nexport const q = 12;" - /file2.ts SVC-2-1 "const a = 1;\nconst g = p + q;\nfunction e();\nconst f = r + s;\nconst a = 1;\nconst b = 2;\n;" - /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export const p = 10;\nexport const q = 12;" - /file2.ts SVC-2-2 "const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;;" - /file3.ts Text-1 "export const r = 10;\nexport const s = 12;" - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] response: - { - "seq": 0, - "type": "response", - "command": "getPostPasteImportFixes", - "request_seq": 3, - "success": true, - "performanceData": { - "updateGraphDurationMs": * - }, - "body": { - "edits": [ - { - "fileName": "/file2.ts", - "textChanges": [ - { - "start": { - "line": 1, - "offset": 1 - }, - "end": { - "line": 1, - "offset": 1 - }, - "newText": "import { p, q } from \"./file1\";\nimport { r, s } from \"./file3\";\n\n" - }, - { - "start": { - "line": 2, - "offset": 1 - }, - "end": { - "line": 3, - "offset": 1 - }, - "newText": "const g = p + q;\nfunction e();\nconst f = r + s;\n" - }, - { - "start": { - "line": 4, - "offset": 1 - }, - "end": { - "line": 4, - "offset": 13 - }, - "newText": "const g = p + q;\nfunction e();\nconst f = r + s;\n" - } - ] - } - ] - } - } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes2.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes2.js deleted file mode 100644 index 52bad6f959f07..0000000000000 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_multiplePastes2.js +++ /dev/null @@ -1,356 +0,0 @@ -currentDirectory:: / useCaseSensitiveFileNames: false -Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist -//// [/file1.ts] -import { aa, bb } from "./other"; -export const r = 10; -export const s = 12; -export const t = aa + bb + r + s; -const u = 1; - -//// [/lib.d.ts] -lib.d.ts-Text - -//// [/lib.decorators.d.ts] -lib.decorators.d.ts-Text - -//// [/lib.decorators.legacy.d.ts] -lib.decorators.legacy.d.ts-Text - -//// [/other.ts] -export const aa = 1; -export const bb = 2; - -//// [/target.ts] -const a = 1; -const b = 2; -const c = 3; -const d = 4; - -//// [/tsconfig.json] -{ "files": ["file1.ts", "target.ts", "other.ts"] } - - -Info seq [hh:mm:ss:mss] request: - { - "seq": 0, - "type": "request", - "arguments": { - "file": "/file1.ts" - }, - "command": "open" - } -Info seq [hh:mm:ss:mss] Search path: / -Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json -Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "projectLoadingStart", - "body": { - "projectName": "/tsconfig.json", - "reason": "Creating possible configured project for /file1.ts to open" - } - } -Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { - "rootNames": [ - "/file1.ts", - "/target.ts", - "/other.ts" - ], - "options": { - "configFilePath": "/tsconfig.json" - } -} -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /target.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /other.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" - /file1.ts SVC-1-0 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" - /target.ts Text-1 "const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;" - - - lib.d.ts - Default library for target 'es5' - lib.decorators.d.ts - Library referenced via 'decorators' from file 'lib.d.ts' - lib.decorators.legacy.d.ts - Library referenced via 'decorators.legacy' from file 'lib.d.ts' - other.ts - Imported via "./other" from file 'file1.ts' - Part of 'files' list in tsconfig.json - file1.ts - Part of 'files' list in tsconfig.json - target.ts - Part of 'files' list in tsconfig.json - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "projectLoadingFinish", - "body": { - "projectName": "/tsconfig.json" - } - } -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "configFileDiag", - "body": { - "triggerFile": "/file1.ts", - "configFile": "/tsconfig.json", - "diagnostics": [] - } - } -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Open files: -Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -After Request -watchedFiles:: -/lib.d.ts: *new* - {"pollingInterval":500} -/lib.decorators.d.ts: *new* - {"pollingInterval":500} -/lib.decorators.legacy.d.ts: *new* - {"pollingInterval":500} -/other.ts: *new* - {"pollingInterval":500} -/target.ts: *new* - {"pollingInterval":500} -/tsconfig.json: *new* - {"pollingInterval":2000} - -Info seq [hh:mm:ss:mss] request: - { - "seq": 1, - "type": "request", - "arguments": { - "file": "/target.ts" - }, - "command": "open" - } -Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /target.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Search path: / -Info seq [hh:mm:ss:mss] For info: /target.ts :: Config file name: /tsconfig.json -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Open files: -Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -Info seq [hh:mm:ss:mss] FileName: /target.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -After Request -watchedFiles:: -/lib.d.ts: - {"pollingInterval":500} -/lib.decorators.d.ts: - {"pollingInterval":500} -/lib.decorators.legacy.d.ts: - {"pollingInterval":500} -/other.ts: - {"pollingInterval":500} -/tsconfig.json: - {"pollingInterval":2000} - -watchedFiles *deleted*:: -/target.ts: - {"pollingInterval":500} - -Info seq [hh:mm:ss:mss] request: - { - "seq": 2, - "type": "request", - "arguments": { - "formatOptions": { - "indentSize": 4, - "tabSize": 4, - "newLineCharacter": "\n", - "convertTabsToSpaces": true, - "indentStyle": 2, - "insertSpaceAfterConstructor": false, - "insertSpaceAfterCommaDelimiter": true, - "insertSpaceAfterSemicolonInForStatements": true, - "insertSpaceBeforeAndAfterBinaryOperators": true, - "insertSpaceAfterKeywordsInControlFlowStatements": true, - "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, - "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, - "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, - "insertSpaceBeforeFunctionParenthesis": false, - "placeOpenBraceOnNewLineForFunctions": false, - "placeOpenBraceOnNewLineForControlBlocks": false, - "semicolons": "ignore", - "trimTrailingWhitespace": true, - "indentSwitchCase": true - } - }, - "command": "configure" - } -Info seq [hh:mm:ss:mss] Format host information updated -Info seq [hh:mm:ss:mss] response: - { - "seq": 0, - "type": "response", - "command": "configure", - "request_seq": 2, - "success": true - } -Info seq [hh:mm:ss:mss] request: - { - "seq": 3, - "type": "request", - "arguments": { - "file": "/target.ts", - "startLine": 2, - "startOffset": 1, - "endLine": 3, - "endOffset": 1, - "targetFile": "/target.ts", - "pastes": [ - { - "text": "export const t = aa + bb + r + s;\nconst u = 1;\n", - "range": { - "file": "/target.ts", - "startLine": 2, - "startOffset": 1, - "endLine": 3, - "endOffset": 1 - } - }, - { - "text": "export const t = aa + bb + r + s;\nconst u = 1;\n", - "range": { - "file": "/target.ts", - "startLine": 4, - "startOffset": 1, - "endLine": 4, - "endOffset": 13 - } - } - ], - "originalFile": "file1.ts", - "copyRange": { - "start": { - "line": 3, - "offset": 0 - }, - "end": { - "line": 4, - "offset": 12 - } - } - }, - "command": "getPostPasteImportFixes" - } -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" - /file1.ts SVC-1-0 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" - /target.ts SVC-2-1 "const a = 1;\nexport const t = aa + bb + r + s;\nconst u = 1;\nconst a = 1;\nconst b = 2;\n;" - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results -Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms -Info seq [hh:mm:ss:mss] getExportInfoMap: cache hit -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (6) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /other.ts Text-1 "export const aa = 1;\nexport const bb = 2;" - /file1.ts SVC-1-0 "import { aa, bb } from \"./other\";\nexport const r = 10;\nexport const s = 12;\nexport const t = aa + bb + r + s;\nconst u = 1;" - /target.ts SVC-2-2 "const a = 1;\nconst b = 2;\nconst c = 3;\nconst d = 4;;" - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] response: - { - "seq": 0, - "type": "response", - "command": "getPostPasteImportFixes", - "request_seq": 3, - "success": true, - "performanceData": { - "updateGraphDurationMs": * - }, - "body": { - "edits": [ - { - "fileName": "/target.ts", - "textChanges": [ - { - "start": { - "line": 1, - "offset": 1 - }, - "end": { - "line": 1, - "offset": 1 - }, - "newText": "import { r, s } from \"./file1\";\n\n" - }, - { - "start": { - "line": 1, - "offset": 1 - }, - "end": { - "line": 1, - "offset": 1 - }, - "newText": "import { aa, bb } from \"./other\";\n\n" - }, - { - "start": { - "line": 2, - "offset": 1 - }, - "end": { - "line": 3, - "offset": 1 - }, - "newText": "export const t = aa + bb + r + s;\nconst u = 1;\n" - }, - { - "start": { - "line": 4, - "offset": 1 - }, - "end": { - "line": 4, - "offset": 13 - }, - "newText": "export const t = aa + bb + r + s;\nconst u = 1;\n" - } - ] - } - ] - } - } \ No newline at end of file diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_unknownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_unknownSourceFile.js deleted file mode 100644 index 3e21b762917c8..0000000000000 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFix_unknownSourceFile.js +++ /dev/null @@ -1,292 +0,0 @@ -currentDirectory:: / useCaseSensitiveFileNames: false -Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist -//// [/file1.ts] -export interface Test1 {} -export interface Test2 {} -export interface Test3 {} -export interface Test4 {} - -//// [/file2.ts] -const a = 10; -const b = 10; -const c = 10; - -//// [/lib.d.ts] -lib.d.ts-Text - -//// [/lib.decorators.d.ts] -lib.decorators.d.ts-Text - -//// [/lib.decorators.legacy.d.ts] -lib.decorators.legacy.d.ts-Text - -//// [/tsconfig.json] -{ "files": ["file1.ts", "file2.ts"] } - - -Info seq [hh:mm:ss:mss] request: - { - "seq": 0, - "type": "request", - "arguments": { - "file": "/file1.ts" - }, - "command": "open" - } -Info seq [hh:mm:ss:mss] Search path: / -Info seq [hh:mm:ss:mss] For info: /file1.ts :: Config file name: /tsconfig.json -Info seq [hh:mm:ss:mss] Creating configuration project /tsconfig.json -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /tsconfig.json 2000 undefined Project: /tsconfig.json WatchType: Config file -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "projectLoadingStart", - "body": { - "projectName": "/tsconfig.json", - "reason": "Creating possible configured project for /file1.ts to open" - } - } -Info seq [hh:mm:ss:mss] Config: /tsconfig.json : { - "rootNames": [ - "/file1.ts", - "/file2.ts" - ], - "options": { - "configFilePath": "/tsconfig.json" - } -} -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (5) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" - /file2.ts Text-1 "const a = 10;\nconst b = 10;\nconst c = 10;" - - - lib.d.ts - Default library for target 'es5' - lib.decorators.d.ts - Library referenced via 'decorators' from file 'lib.d.ts' - lib.decorators.legacy.d.ts - Library referenced via 'decorators.legacy' from file 'lib.d.ts' - file1.ts - Part of 'files' list in tsconfig.json - file2.ts - Part of 'files' list in tsconfig.json - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "projectLoadingFinish", - "body": { - "projectName": "/tsconfig.json" - } - } -Info seq [hh:mm:ss:mss] event: - { - "seq": 0, - "type": "event", - "event": "configFileDiag", - "body": { - "triggerFile": "/file1.ts", - "configFile": "/tsconfig.json", - "diagnostics": [] - } - } -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (5) - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Open files: -Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -After Request -watchedFiles:: -/file2.ts: *new* - {"pollingInterval":500} -/lib.d.ts: *new* - {"pollingInterval":500} -/lib.decorators.d.ts: *new* - {"pollingInterval":500} -/lib.decorators.legacy.d.ts: *new* - {"pollingInterval":500} -/tsconfig.json: *new* - {"pollingInterval":2000} - -Info seq [hh:mm:ss:mss] request: - { - "seq": 1, - "type": "request", - "arguments": { - "file": "/file2.ts" - }, - "command": "open" - } -Info seq [hh:mm:ss:mss] FileWatcher:: Close:: WatchInfo: /file2.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Search path: / -Info seq [hh:mm:ss:mss] For info: /file2.ts :: Config file name: /tsconfig.json -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (5) - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Open files: -Info seq [hh:mm:ss:mss] FileName: /file1.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -Info seq [hh:mm:ss:mss] FileName: /file2.ts ProjectRootPath: undefined -Info seq [hh:mm:ss:mss] Projects: /tsconfig.json -After Request -watchedFiles:: -/lib.d.ts: - {"pollingInterval":500} -/lib.decorators.d.ts: - {"pollingInterval":500} -/lib.decorators.legacy.d.ts: - {"pollingInterval":500} -/tsconfig.json: - {"pollingInterval":2000} - -watchedFiles *deleted*:: -/file2.ts: - {"pollingInterval":500} - -Info seq [hh:mm:ss:mss] request: - { - "seq": 2, - "type": "request", - "arguments": { - "formatOptions": { - "indentSize": 4, - "tabSize": 4, - "newLineCharacter": "\n", - "convertTabsToSpaces": true, - "indentStyle": 2, - "insertSpaceAfterConstructor": false, - "insertSpaceAfterCommaDelimiter": true, - "insertSpaceAfterSemicolonInForStatements": true, - "insertSpaceBeforeAndAfterBinaryOperators": true, - "insertSpaceAfterKeywordsInControlFlowStatements": true, - "insertSpaceAfterFunctionKeywordForAnonymousFunctions": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, - "insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true, - "insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false, - "insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, - "insertSpaceBeforeFunctionParenthesis": false, - "placeOpenBraceOnNewLineForFunctions": false, - "placeOpenBraceOnNewLineForControlBlocks": false, - "semicolons": "ignore", - "trimTrailingWhitespace": true, - "indentSwitchCase": true - } - }, - "command": "configure" - } -Info seq [hh:mm:ss:mss] Format host information updated -Info seq [hh:mm:ss:mss] response: - { - "seq": 0, - "type": "response", - "command": "configure", - "request_seq": 2, - "success": true - } -Info seq [hh:mm:ss:mss] request: - { - "seq": 3, - "type": "request", - "arguments": { - "file": "/file2.ts", - "startLine": 2, - "startOffset": 1, - "endLine": 2, - "endOffset": 14, - "targetFile": "/file2.ts", - "pastes": [ - { - "text": "interface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }", - "range": { - "file": "/file2.ts", - "startLine": 2, - "startOffset": 1, - "endLine": 2, - "endOffset": 14 - } - } - ] - }, - "command": "getPostPasteImportFixes" - } -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (5) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" - /file2.ts SVC-2-1 "const a = 10;\ninterface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }const a = 10;\nconst b = 10;;" - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms -Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) -Info seq [hh:mm:ss:mss] Files (5) - /lib.d.ts Text-1 lib.d.ts-Text - /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text - /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text - /file1.ts SVC-1-0 "export interface Test1 {}\nexport interface Test2 {}\nexport interface Test3 {}\nexport interface Test4 {}" - /file2.ts SVC-2-2 "const a = 10;\nconst b = 10;\nconst c = 10;;" - -Info seq [hh:mm:ss:mss] ----------------------------------------------- -Info seq [hh:mm:ss:mss] response: - { - "seq": 0, - "type": "response", - "command": "getPostPasteImportFixes", - "request_seq": 3, - "success": true, - "performanceData": { - "updateGraphDurationMs": * - }, - "body": { - "edits": [ - { - "fileName": "/file2.ts", - "textChanges": [ - { - "start": { - "line": 1, - "offset": 1 - }, - "end": { - "line": 1, - "offset": 1 - }, - "newText": "import { Test1, Test2, Test3, Test4 } from \"./file1\";\n\n" - }, - { - "start": { - "line": 2, - "offset": 1 - }, - "end": { - "line": 2, - "offset": 14 - }, - "newText": "interface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }" - } - ] - } - ] - } - } \ No newline at end of file From bfe79a969de1549e2b560f1cc37e45863ee2f0d4 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Fri, 9 Feb 2024 14:18:45 -0800 Subject: [PATCH 09/18] fixing eslint errors --- src/harness/client.ts | 6 +++--- src/harness/fourslashImpl.ts | 1 - src/harness/fourslashInterfaceImpl.ts | 4 ++-- src/server/project.ts | 6 ------ src/server/protocol.ts | 2 +- src/server/session.ts | 2 +- src/services/postPasteImportFixes.ts | 18 +++++++++--------- src/services/services.ts | 6 +++--- src/services/types.ts | 4 +--- ...mportNameCodeFix_add_all_missing_imports.ts | 9 ++------- 10 files changed, 22 insertions(+), 36 deletions(-) diff --git a/src/harness/client.ts b/src/harness/client.ts index ae166c06ed207..149e43631d69f 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -1013,7 +1013,7 @@ export class SessionClient implements LanguageService { getPostPasteImportFixes( targetFile: string, - pastes: Array<{ text: string; range: TextRange }>, + pastes: { text: string; range: TextRange }[], _preferences: UserPreferences, _formatOptions: FormatCodeSettings, copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number } }): PostPasteImportFixes { @@ -1021,7 +1021,7 @@ export class SessionClient implements LanguageService { const args: protocol.GetPostPasteImportFixesRequestArgs = { file: targetFile, pastes: arrayFrom(pastes.map(paste => ({text: paste.text, range: { start: this.positionToOneBasedLineOffset(targetFile, paste.range.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.range.end)}}))), - copySpan: copySpan + copySpan } const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); const response = this.processResponse(request); @@ -1029,7 +1029,7 @@ export class SessionClient implements LanguageService { return { edits: []}; } const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body.edits); - return { edits: edits }; + return { edits }; } getProgram(): Program { diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 7bfa915f924e2..5518a2526d2ef 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -10,7 +10,6 @@ import { } from "./tsserverLogger"; import ArrayOrSingle = FourSlashInterface.ArrayOrSingle; -import { arrayFrom } from "./_namespaces/ts"; export const enum FourSlashTestType { Native, diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 72fa4a5e047ea..1906512f76a9e 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1886,7 +1886,7 @@ export interface VerifyCodeFixAllOptions { export interface VerifyPostPasteImportFix { targetFile: string; - pastes: Array<{text: string; range: ts.TextRange}>; + pastes: { text: string; range: ts.TextRange }[]; preferences: ts.UserPreferences; copySpan?: { file: string, start: Location, end: Location } } @@ -1933,7 +1933,7 @@ export interface MoveToFileOptions { export interface PostPasteImportFixOptions { readonly newFileContents: { readonly [fileName: string]: string; }; - readonly pastes: Array<{text: string; range: ts.TextRange}>; + readonly pastes: { text: string; range: ts.TextRange }[]; readonly preferences: ts.UserPreferences; readonly copySpan?: { file: string, start: Location, end: Location }; } diff --git a/src/server/project.ts b/src/server/project.ts index 35d12cec6071f..a7e1871623698 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -1,6 +1,3 @@ -import { info } from "console"; -import { FormatContext } from "../services/_namespaces/ts.formatting"; -import { FixInfo, ImportFixWithModuleSpecifier, sortFixInfo } from "../services/codefixes/importFixes"; import * as ts from "./_namespaces/ts"; import { addRange, @@ -23,7 +20,6 @@ import { containsPath, createCacheableExportInfoMap, createLanguageService, - createPackageJsonImportFilter, createResolutionCache, createSymlinkCache, Debug, @@ -69,7 +65,6 @@ import { HasInvalidatedLibResolutions, HasInvalidatedResolutions, HostCancellationToken, - ImportClause, inferredTypesContainingFile, InstallPackageOptions, IScriptSnapshot, @@ -125,7 +120,6 @@ import { StringLiteralLike, stripQuotes, StructureIsReused, - SymbolExportInfo, SymlinkCache, ThrottledCancellationToken, timestamp, diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 9ea16d803c8e4..e82a954a4564d 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -641,7 +641,7 @@ export interface GetPostPasteImportFixesRequest extends Request { } export type GetPostPasteImportFixesRequestArgs = FileRequestArgs & { - pastes: Array<{ text: string; range: TextSpan }>, + pastes: {text: string; range: TextSpan}[], copySpan?: FileSpan, } export interface GetPostPasteImportFixesResponse extends Response { diff --git a/src/server/session.ts b/src/server/session.ts index a14467fd0345e..8a8d444a04b2d 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2799,7 +2799,7 @@ export class Session implements EventSender { private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction | undefined { const { file, project } = this.getFileAndProject(args); - const pastes = arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange({file: file, startLine: paste.range.start.line, startOffset: paste.range.start.offset, endLine: paste.range.end.line, endOffset: paste.range.end.offset}, project.getScriptInfoForNormalizedPath(file)!)})) + const pastes = arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange({ file, startLine: paste.range.start.line, startOffset: paste.range.start.offset, endLine: paste.range.end.line, endOffset: paste.range.end.offset }, project.getScriptInfoForNormalizedPath(file)!)})) const result = project.getLanguageService().getPostPasteImportFixes( file, pastes, this.getPreferences(file), this.getFormatOptions(file), args.copySpan); if (result === undefined) { return undefined; diff --git a/src/services/postPasteImportFixes.ts b/src/services/postPasteImportFixes.ts index 611e564e74b4f..e144c4ede50f6 100644 --- a/src/services/postPasteImportFixes.ts +++ b/src/services/postPasteImportFixes.ts @@ -1,7 +1,7 @@ import { addRange, append } from "../compiler/core"; -import { SourceFile, Statement, UserPreferences, TypeChecker, AnyImportOrRequireStatement, Identifier, ModifierFlags, Program, TextRange, CancellationToken, ImportClause, ObjectBindingPattern, TypeOnlyAliasDeclaration, SymbolFlags } from "../compiler/types"; +import { AnyImportOrRequireStatement, CancellationToken, Identifier, ModifierFlags, Program, SourceFile, Statement, SymbolFlags,TextRange, TypeChecker, UserPreferences } from "../compiler/types"; import { hasSyntacticModifier, skipAlias } from "../compiler/utilities"; -import { codefix, Debug, factory, fileShouldUseJavaScriptRequire, forEachChild, formatting, getQuotePreference, ImportKind, insertImports, nodeSeenTracker, Symbol, SymbolExportInfo, textChanges, isIdentifier } from "./_namespaces/ts"; +import { codefix, Debug, factory, fileShouldUseJavaScriptRequire, forEachChild, formatting, getQuotePreference, insertImports, isIdentifier,nodeSeenTracker, Symbol, textChanges } from "./_namespaces/ts"; import { addExportToChanges, filterImport, forEachImportInStatement, getExistingLocals, getTopLevelDeclarationStatement, getUsageInfo, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./refactors/moveToFile"; import { CodeFixContextBase, FileTextChanges, LanguageServiceHost, PostPasteImportFixes } from "./types"; @@ -9,7 +9,7 @@ import { CodeFixContextBase, FileTextChanges, LanguageServiceHost, PostPasteImpo export function postPasteImportFixesProvider( targetFile: SourceFile, host: LanguageServiceHost, - pastes: Array<{ text: string; range: TextRange }>, + pastes: { text: string; range: TextRange }[], preferences: UserPreferences, formatContext: formatting.FormatContext, cancellationToken: CancellationToken, @@ -24,7 +24,7 @@ export function postPasteImportFixesProvider( function postPasteFixes ( targetFile: SourceFile, host: LanguageServiceHost, - pastes: Array<{ text: string; range: TextRange }>, + pastes: { text: string; range: TextRange }[], preferences: UserPreferences, formatContext: formatting.FormatContext, cancellationToken: CancellationToken, @@ -32,7 +32,7 @@ function postPasteFixes ( originalFile?: SourceFile, copyLocation?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }}) { const updatedTargetFile = host.updateTargetFile?.(targetFile.fileName, targetFile.getText(), targetFile.getText().slice(0, pastes[0].range.pos) + pastes[0].text + targetFile.getText().slice(pastes[0].range.end)); - let statements: Statement[] = []; + const statements: Statement[] = []; Debug.assert(updatedTargetFile && updatedTargetFile.updatedFile && updatedTargetFile.originalProgram && updatedTargetFile.updatedProgram); if (originalFile) { @@ -51,10 +51,10 @@ function postPasteFixes ( const context: CodeFixContextBase = { sourceFile: updatedTargetFile.updatedFile, program: updatedTargetFile.originalProgram, - cancellationToken: cancellationToken, - host: host, - preferences: preferences, - formatContext: formatContext + cancellationToken, + host, + preferences, + formatContext } const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); forEachChild(updatedTargetFile.updatedFile, function cb(node) { diff --git a/src/services/services.ts b/src/services/services.ts index aad974e869165..9733e6e616b90 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -241,6 +241,8 @@ import { Path, positionIsSynthesized, PossibleProgramFileInfo, + PostPasteImportFixes, + postPasteImportFixes, PragmaMap, PrivateIdentifier, Program, @@ -319,8 +321,6 @@ import { updateSourceFile, UserPreferences, VariableDeclaration, - postPasteImportFixes, - PostPasteImportFixes, } from "./_namespaces/ts"; import * as NavigateTo from "./_namespaces/ts.NavigateTo"; import * as NavigationBar from "./_namespaces/ts.NavigationBar"; @@ -2093,7 +2093,7 @@ export function createLanguageService( function getPostPasteImportFixes ( targetFile: string, - pastes: Array<{ text: string; range: TextRange }>, + pastes: { text: string; range: TextRange }[], preferences: UserPreferences, formatOptions: FormatCodeSettings, copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }} diff --git a/src/services/types.ts b/src/services/types.ts index 94d7425445528..3093f6aac8814 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -42,8 +42,6 @@ import { TextSpan, UserPreferences, } from "./_namespaces/ts"; -import { FixInfo } from "./_namespaces/ts.codefix"; -import { FormatContext } from "./formatting/formatting"; declare module "../compiler/types" { // Module transform: converted from interface augmentation @@ -689,7 +687,7 @@ export interface LanguageService { dispose(): void; getPostPasteImportFixes( targetFile: string, - pastes: Array<{ text: string; range: TextRange }>, + pastes: { text: string; range: TextRange }[], preferences: UserPreferences, formatOptions: FormatCodeSettings, copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }}): PostPasteImportFixes; diff --git a/tests/cases/fourslash/importNameCodeFix_add_all_missing_imports.ts b/tests/cases/fourslash/importNameCodeFix_add_all_missing_imports.ts index 0386beb369950..524a4979f1bc7 100644 --- a/tests/cases/fourslash/importNameCodeFix_add_all_missing_imports.ts +++ b/tests/cases/fourslash/importNameCodeFix_add_all_missing_imports.ts @@ -2,19 +2,15 @@ // @Filename: /a.ts ////export const a: number; -////export const k: number; + // @Filename: /b.ts ////export const b: number; // @Filename: /c.ts ////export const c: number; -// @Filename: /d.ts -////export const k: number; - // @Filename: /main.ts ////a; -////k; ////b; ////c; @@ -23,12 +19,11 @@ verify.codeFixAll({ fixId: "fixMissingImport", fixAllDescription: "Add all missing imports", newFileContent: -`import { a, k } from "./a"; +`import { a } from "./a"; import { b } from "./b"; import { c } from "./c"; a; -k; b; c;`, }); From ab542b5db8c81733dbedc1a70dc1f0ed2f12f5f0 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Mon, 12 Feb 2024 11:13:09 -0800 Subject: [PATCH 10/18] fiixng formatting and baseline changes --- src/harness/client.ts | 18 +- src/harness/fourslashImpl.ts | 2 +- src/harness/fourslashInterfaceImpl.ts | 12 +- src/server/project.ts | 2 +- src/server/protocol.ts | 6 +- src/server/session.ts | 6 +- .../_namespaces/ts.postPasteImportFixes.ts | 2 +- src/services/codefixes/importFixes.ts | 4 +- src/services/postPasteImportFixes.ts | 103 ++++++--- src/services/services.ts | 12 +- src/services/types.ts | 13 +- src/testRunner/tests.ts | 2 +- .../tsserver/postPasteImportFixes.ts | 8 +- .../reference/APILibCheck.errors.txt | 47 ++++ tests/baselines/reference/api/typescript.d.ts | 73 +++++++ .../Returns-the-same-file-unchanged-.js | 203 ++++++++++++++++++ 16 files changed, 444 insertions(+), 69 deletions(-) create mode 100644 tests/baselines/reference/APILibCheck.errors.txt create mode 100644 tests/baselines/reference/tsserver/getPostPasteImportFixes/Returns-the-same-file-unchanged-.js diff --git a/src/harness/client.ts b/src/harness/client.ts index 149e43631d69f..1e022eb7be7f6 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -1013,20 +1013,20 @@ export class SessionClient implements LanguageService { getPostPasteImportFixes( targetFile: string, - pastes: { text: string; range: TextRange }[], - _preferences: UserPreferences, - _formatOptions: FormatCodeSettings, - copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number } }): PostPasteImportFixes { - + pastes: { text: string; range: TextRange; }[], + _preferences: UserPreferences, + _formatOptions: FormatCodeSettings, + copySpan?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, + ): PostPasteImportFixes { const args: protocol.GetPostPasteImportFixesRequestArgs = { file: targetFile, - pastes: arrayFrom(pastes.map(paste => ({text: paste.text, range: { start: this.positionToOneBasedLineOffset(targetFile, paste.range.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.range.end)}}))), - copySpan - } + pastes: arrayFrom(pastes.map(paste => ({ text: paste.text, range: { start: this.positionToOneBasedLineOffset(targetFile, paste.range.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.range.end) } }))), + copySpan, + }; const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); const response = this.processResponse(request); if (!response.body) { - return { edits: []}; + return { edits: [] }; } const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body.edits); return { edits }; diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 5518a2526d2ef..f6c6aaa316ad5 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -3563,7 +3563,7 @@ export class TestState { } public verifyPostPasteImportFixes(options: FourSlashInterface.PostPasteImportFixOptions): void { - const editInfo = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, options.pastes, options.preferences, this.formatCodeSettings, options.copySpan); + const editInfo = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, options.pastes, options.preferences, this.formatCodeSettings, options.copySpan); this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits); } diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 1906512f76a9e..b6a7e5b76ead4 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1,4 +1,6 @@ -import { Location } from "../server/protocol"; +import { + Location, +} from "../server/protocol"; import * as FourSlash from "./_namespaces/FourSlash"; import * as ts from "./_namespaces/ts"; @@ -1886,9 +1888,9 @@ export interface VerifyCodeFixAllOptions { export interface VerifyPostPasteImportFix { targetFile: string; - pastes: { text: string; range: ts.TextRange }[]; + pastes: { text: string; range: ts.TextRange; }[]; preferences: ts.UserPreferences; - copySpan?: { file: string, start: Location, end: Location } + copySpan?: { file: string; start: Location; end: Location; }; } export interface VerifyRefactorOptions { @@ -1933,9 +1935,9 @@ export interface MoveToFileOptions { export interface PostPasteImportFixOptions { readonly newFileContents: { readonly [fileName: string]: string; }; - readonly pastes: { text: string; range: ts.TextRange }[]; + readonly pastes: { text: string; range: ts.TextRange; }[]; readonly preferences: ts.UserPreferences; - readonly copySpan?: { file: string, start: Location, end: Location }; + readonly copySpan?: { file: string; start: Location; end: Location; }; } export type RenameLocationsOptions = readonly RenameLocationOptions[] | { diff --git a/src/server/project.ts b/src/server/project.ts index a7e1871623698..80ca6d30398c7 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2213,7 +2213,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): { updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: ts.Program | undefined } { + updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): { updatedFile: SourceFile | undefined; updatedProgram: Program | undefined; originalProgram: ts.Program | undefined; } { const originalProgram = this.program; this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length, pastedText); this.updateGraph(); diff --git a/src/server/protocol.ts b/src/server/protocol.ts index e82a954a4564d..7f6fee9920b13 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -641,9 +641,9 @@ export interface GetPostPasteImportFixesRequest extends Request { } export type GetPostPasteImportFixesRequestArgs = FileRequestArgs & { - pastes: {text: string; range: TextSpan}[], - copySpan?: FileSpan, -} + pastes: { text: string; range: TextSpan; }[]; + copySpan?: FileSpan; +}; export interface GetPostPasteImportFixesResponse extends Response { body: PostPasteImportAction; } diff --git a/src/server/session.ts b/src/server/session.ts index 8a8d444a04b2d..050323155381c 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2799,8 +2799,8 @@ export class Session implements EventSender { private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction | undefined { const { file, project } = this.getFileAndProject(args); - const pastes = arrayFrom(args.pastes).map(paste => ({text: paste.text, range: this.getRange({ file, startLine: paste.range.start.line, startOffset: paste.range.start.offset, endLine: paste.range.end.line, endOffset: paste.range.end.offset }, project.getScriptInfoForNormalizedPath(file)!)})) - const result = project.getLanguageService().getPostPasteImportFixes( file, pastes, this.getPreferences(file), this.getFormatOptions(file), args.copySpan); + const pastes = arrayFrom(args.pastes).map(paste => ({ text: paste.text, range: this.getRange({ file, startLine: paste.range.start.line, startOffset: paste.range.start.offset, endLine: paste.range.end.line, endOffset: paste.range.end.offset }, project.getScriptInfoForNormalizedPath(file)!) })); + const result = project.getLanguageService().getPostPasteImportFixes(file, pastes, this.getPreferences(file), this.getFormatOptions(file), args.copySpan); if (result === undefined) { return undefined; } @@ -2941,7 +2941,7 @@ export class Session implements EventSender { } private mapPostPasteAction({ edits }: PostPasteImportFixes): protocol.PostPasteImportAction { - return { edits: this.mapTextChangesToCodeEdits(edits)}; + return { edits: this.mapTextChangesToCodeEdits(edits) }; } private mapTextChangesToCodeEdits(textChanges: readonly FileTextChanges[]): protocol.FileCodeEdits[] { diff --git a/src/services/_namespaces/ts.postPasteImportFixes.ts b/src/services/_namespaces/ts.postPasteImportFixes.ts index b75b8ec1d96cc..0f1f3e8189d63 100644 --- a/src/services/_namespaces/ts.postPasteImportFixes.ts +++ b/src/services/_namespaces/ts.postPasteImportFixes.ts @@ -1 +1 @@ -export * from "../postPasteImportFixes"; \ No newline at end of file +export * from "../postPasteImportFixes"; diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 66a4896e0f97b..ce2ee8c6ea3ed 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -244,7 +244,7 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu if (!info || !info.length) return; addImport(first(info)); } - + function addImportFromDiagnostic(diagnostic: DiagnosticWithLocation, context: CodeFixContextBase) { const info = getFixInfos(context, diagnostic.code, diagnostic.start, useAutoImportProvider); if (!info || !info.length) return; @@ -1017,7 +1017,7 @@ export function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModul compareModuleSpecifiers(a.fix, b.fix, sourceFile, program, packageJsonImportFilter.allowsImportingSpecifier, _toPath)); } -function getFixInfosWithoutDiagnostic(context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly FixInfo[] | undefined { +function getFixInfosWithoutDiagnostic(context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean): readonly FixInfo[] | undefined { const info = getFixesInfoForNonUMDImport(context, symbolToken, useAutoImportProvider); const packageJsonImportFilter = createPackageJsonImportFilter(context.sourceFile, context.preferences, context.host); return info && sortFixInfo(info, context.sourceFile, context.program, packageJsonImportFilter, context.host); diff --git a/src/services/postPasteImportFixes.ts b/src/services/postPasteImportFixes.ts index e144c4ede50f6..220369ae1cc8c 100644 --- a/src/services/postPasteImportFixes.ts +++ b/src/services/postPasteImportFixes.ts @@ -1,43 +1,91 @@ -import { addRange, append } from "../compiler/core"; -import { AnyImportOrRequireStatement, CancellationToken, Identifier, ModifierFlags, Program, SourceFile, Statement, SymbolFlags,TextRange, TypeChecker, UserPreferences } from "../compiler/types"; -import { hasSyntacticModifier, skipAlias } from "../compiler/utilities"; -import { codefix, Debug, factory, fileShouldUseJavaScriptRequire, forEachChild, formatting, getQuotePreference, insertImports, isIdentifier,nodeSeenTracker, Symbol, textChanges } from "./_namespaces/ts"; -import { addExportToChanges, filterImport, forEachImportInStatement, getExistingLocals, getTopLevelDeclarationStatement, getUsageInfo, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./refactors/moveToFile"; -import { CodeFixContextBase, FileTextChanges, LanguageServiceHost, PostPasteImportFixes } from "./types"; +import { + addRange, + append, +} from "../compiler/core"; +import { + AnyImportOrRequireStatement, + CancellationToken, + Identifier, + ModifierFlags, + Program, + SourceFile, + Statement, + SymbolFlags, + TextRange, + TypeChecker, + UserPreferences, +} from "../compiler/types"; +import { + hasSyntacticModifier, + skipAlias, +} from "../compiler/utilities"; +import { + codefix, + Debug, + factory, + fileShouldUseJavaScriptRequire, + forEachChild, + formatting, + getQuotePreference, + insertImports, + isIdentifier, + nodeSeenTracker, + Symbol, + textChanges, +} from "./_namespaces/ts"; +import { + addExportToChanges, + filterImport, + forEachImportInStatement, + getExistingLocals, + getTopLevelDeclarationStatement, + getUsageInfo, + isTopLevelDeclaration, + makeImportOrRequire, + moduleSpecifierFromImport, + nameOfTopLevelDeclaration, +} from "./refactors/moveToFile"; +import { + CodeFixContextBase, + FileTextChanges, + LanguageServiceHost, + PostPasteImportFixes, +} from "./types"; /** @internal */ export function postPasteImportFixesProvider( - targetFile: SourceFile, + targetFile: SourceFile, host: LanguageServiceHost, - pastes: { text: string; range: TextRange }[], + pastes: { text: string; range: TextRange; }[], preferences: UserPreferences, formatContext: formatting.FormatContext, cancellationToken: CancellationToken, originalFile?: SourceFile, - copyLocation?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }}): PostPasteImportFixes { - + copyLocation?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, +): PostPasteImportFixes { const changes: FileTextChanges[] = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => postPasteFixes(targetFile, host, pastes, preferences, formatContext, cancellationToken, changeTracker, originalFile, copyLocation)); - return { edits: changes }; + return { edits: changes }; } -function postPasteFixes ( - targetFile: SourceFile, +function postPasteFixes( + targetFile: SourceFile, host: LanguageServiceHost, - pastes: { text: string; range: TextRange }[], + pastes: { text: string; range: TextRange; }[], preferences: UserPreferences, formatContext: formatting.FormatContext, cancellationToken: CancellationToken, changes: textChanges.ChangeTracker, originalFile?: SourceFile, - copyLocation?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }}) { + copyLocation?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, +) { const updatedTargetFile = host.updateTargetFile?.(targetFile.fileName, targetFile.getText(), targetFile.getText().slice(0, pastes[0].range.pos) + pastes[0].text + targetFile.getText().slice(pastes[0].range.end)); const statements: Statement[] = []; Debug.assert(updatedTargetFile && updatedTargetFile.updatedFile && updatedTargetFile.originalProgram && updatedTargetFile.updatedProgram); - + if (originalFile) { - addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation ? copyLocation.end.line + 1 : undefined); - const usage = getUsageInfo(originalFile, statements, updatedTargetFile.originalProgram.getTypeChecker(), getExistingLocals(updatedTargetFile.updatedFile, statements, updatedTargetFile.originalProgram.getTypeChecker())); + addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation ? copyLocation.end.line + 1 : undefined); + const usage = getUsageInfo(originalFile, statements, updatedTargetFile.originalProgram.getTypeChecker(), getExistingLocals(updatedTargetFile.updatedFile, statements, updatedTargetFile.originalProgram.getTypeChecker())); const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); const imports = getImportsFromKnownOriginalFile(originalFile, targetFile, updatedTargetFile.updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, preferences, host, updatedTargetFile.originalProgram.getTypeChecker()); @@ -45,7 +93,7 @@ function postPasteFixes ( insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); } importAdder.writeFixes(changes, getQuotePreference(originalFile, preferences)); - host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); + host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); } else { const context: CodeFixContextBase = { @@ -53,14 +101,14 @@ function postPasteFixes ( program: updatedTargetFile.originalProgram, cancellationToken, host, - preferences, - formatContext - } + preferences, + formatContext, + }; const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); forEachChild(updatedTargetFile.updatedFile, function cb(node) { if (isIdentifier(node)) { if (!updatedTargetFile.originalProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ false)) { - //generate imports + // generate imports importAdder.addImportsForUnknownSymbols(context, node, /*useAutoImportProvider*/ true); } } @@ -71,7 +119,7 @@ function postPasteFixes ( importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); } - pastes.forEach(({ text, range}) => { + pastes.forEach(({ text, range }) => { range.pos === range.end ? changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text) : changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text); }); } @@ -86,7 +134,8 @@ function getImportsFromKnownOriginalFile( changes: textChanges.ChangeTracker, preferences: UserPreferences, host: LanguageServiceHost, - checker: TypeChecker) { + checker: TypeChecker, +) { const copiedOldImports: AnyImportOrRequireStatement[] = []; importsToCopy.forEach((isValidTypeOnlyUseSite, symbol) => { try { @@ -134,5 +183,5 @@ function getImportsFromKnownOriginalFile( } }); - return append(copiedOldImports, makeImportOrRequire(targetFile, oldFileDefault, oldFileNamedImports, originalFile.fileName, program, host, useEsModuleSyntax, quotePreference)) -} \ No newline at end of file + return append(copiedOldImports, makeImportOrRequire(targetFile, oldFileDefault, oldFileNamedImports, originalFile.fileName, program, host, useEsModuleSyntax, quotePreference)); +} diff --git a/src/services/services.ts b/src/services/services.ts index 9733e6e616b90..d0bdc5ba92946 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2091,16 +2091,16 @@ export function createLanguageService( }; } - function getPostPasteImportFixes ( + function getPostPasteImportFixes( targetFile: string, - pastes: { text: string; range: TextRange }[], + pastes: { text: string; range: TextRange; }[], preferences: UserPreferences, formatOptions: FormatCodeSettings, - copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }} - ): PostPasteImportFixes{ + copySpan?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, + ): PostPasteImportFixes { synchronizeHostData(); const originalSourceFile = copySpan ? getValidSourceFile(copySpan.file) : undefined; - const edits = postPasteImportFixes.postPasteImportFixesProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host),cancellationToken, originalSourceFile, copySpan); + const edits = postPasteImportFixes.postPasteImportFixesProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host), cancellationToken, originalSourceFile, copySpan); return edits; } @@ -3175,7 +3175,7 @@ export function createLanguageService( uncommentSelection, provideInlayHints, getSupportedCodeFixes, - getPostPasteImportFixes + getPostPasteImportFixes, }; switch (languageServiceMode) { diff --git a/src/services/types.ts b/src/services/types.ts index 3093f6aac8814..8276d39fca5fd 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -431,7 +431,7 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; /** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; - /** @internal */ updateTargetFile?(rootFile: string, targetFileText: string, pastedText: string): { updatedFile: SourceFile | undefined, updatedProgram: Program | undefined, originalProgram: Program | undefined }; + /** @internal */ updateTargetFile?(rootFile: string, targetFileText: string, pastedText: string): { updatedFile: SourceFile | undefined; updatedProgram: Program | undefined; originalProgram: Program | undefined; }; /** @internal */ revertUpdatedFile?(rootFile: string, updatedText: string, originalText: string): void; jsDocParsingMode?: JSDocParsingMode | undefined; } @@ -687,10 +687,11 @@ export interface LanguageService { dispose(): void; getPostPasteImportFixes( targetFile: string, - pastes: { text: string; range: TextRange }[], - preferences: UserPreferences, - formatOptions: FormatCodeSettings, - copySpan?: { file: string, start: { line: number, offset: number }, end: { line: number, offset: number }}): PostPasteImportFixes; + pastes: { text: string; range: TextRange; }[], + preferences: UserPreferences, + formatOptions: FormatCodeSettings, + copySpan?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, + ): PostPasteImportFixes; } export interface JsxClosingTagInfo { @@ -715,7 +716,7 @@ export const enum OrganizeImportsMode { export interface PostPasteImportFixes { edits: readonly FileTextChanges[]; -} +} export interface OrganizeImportsArgs extends CombinedCodeFixScope { /** @deprecated Use `mode` instead */ diff --git a/src/testRunner/tests.ts b/src/testRunner/tests.ts index a7fc40d26c7ff..4be8d6dd1d3f8 100644 --- a/src/testRunner/tests.ts +++ b/src/testRunner/tests.ts @@ -214,4 +214,4 @@ import "./unittests/debugDeprecation"; import "./unittests/tsserver/inconsistentErrorInEditor"; import "./unittests/tsserver/getMoveToRefactoringFileSuggestions"; import "./unittests/skipJSDocParsing"; -import "./unittests/tsserver/postPasteImportFixes"; \ No newline at end of file +import "./unittests/tsserver/postPasteImportFixes"; diff --git a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts index ecb55a5f84af6..6935f487b4d37 100644 --- a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts +++ b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts @@ -12,11 +12,11 @@ import { describe("unittests:: tsserver:: postPasteImportFixes", () => { it("returns the same file unchanged, after updating and reverting changes added to a file", () => { const target: File = { - path : "/project/a/target.ts", + path: "/project/a/target.ts", content: `const a = 1; const b = 2; const c = 3;`, - } + }; const tsconfig: File = { path: "/project/tsconfig.json", content: "{}", @@ -33,10 +33,10 @@ const c = 3;`; const originalContent = target.content; const originalProgram = session.getProjectService().configuredProjects.get(tsconfig.path)!.getLanguageService().getProgram(); - + const hostProject = session.getProjectService().configuredProjects.get(tsconfig.path)!; const updatedContent = hostProject.updateTargetFile(target.path, target.content, pastedText); - + if (updatedContent.updatedFile !== undefined) { hostProject.revertUpdatedFile(target.path, updatedContent.updatedFile.getText(), originalContent); } diff --git a/tests/baselines/reference/APILibCheck.errors.txt b/tests/baselines/reference/APILibCheck.errors.txt new file mode 100644 index 0000000000000..b81eac4cd40b5 --- /dev/null +++ b/tests/baselines/reference/APILibCheck.errors.txt @@ -0,0 +1,47 @@ +typescript.d.ts(10425,55): error TS2304: Cannot find name 'SymbolExportInfo'. +typescript.d.ts(10426,90): error TS2304: Cannot find name 'SymbolExportInfo'. +typescript.d.ts(10426,120): error TS2304: Cannot find name 'FixAddToExistingImportInfo'. +typescript.d.ts(10438,38): error TS2304: Cannot find name 'PackageJsonImportFilter'. +typescript.d.ts(10443,45): error TS2552: Cannot find name 'FixUseNamespaceImport'. Did you mean 'NamespaceImport'? +typescript.d.ts(10443,69): error TS2304: Cannot find name 'FixAddJsdocTypeImport'. +typescript.d.ts(10443,93): error TS2304: Cannot find name 'FixAddToExistingImport'. +typescript.d.ts(10443,118): error TS2304: Cannot find name 'FixAddNewImport'. +typescript.d.ts(10445,27): error TS2304: Cannot find name 'ImportFix'. +typescript.internal.d.ts(25311,120): error TS2304: Cannot find name 'FixAddToExistingImportInfo'. +typescript.internal.d.ts(25365,45): error TS2304: Cannot find name 'FixUseNamespaceImport'. +typescript.internal.d.ts(25365,69): error TS2304: Cannot find name 'FixAddJsdocTypeImport'. +typescript.internal.d.ts(25365,93): error TS2304: Cannot find name 'FixAddToExistingImport'. +typescript.internal.d.ts(25365,118): error TS2304: Cannot find name 'FixAddNewImport'. +typescript.internal.d.ts(25367,27): error TS2304: Cannot find name 'ImportFix'. + + +==== index.ts (0 errors) ==== + import ts = require("typescript"); + import tsInternal = require("typescript-internal"); + import tsserverlibrary = require("tsserverlibrary"); + import tsserverlibraryInternal = require("tsserverlibrary-internal"); + +==== node_modules/typescript/package.json (0 errors) ==== + { + "name": "typescript", + "types": "/.ts/typescript.d.ts" + } + +==== node_modules/typescript-internal/package.json (0 errors) ==== + { + "name": "typescript-internal", + "types": "/.ts/typescript.internal.d.ts" + } + +==== node_modules/tsserverlibrary/package.json (0 errors) ==== + { + "name": "tsserverlibrary", + "types": "/.ts/tsserverlibrary.d.ts" + } + +==== node_modules/tsserverlibrary-internal/package.json (0 errors) ==== + { + "name": "tsserverlibrary-internal", + "types": "/.ts/tsserverlibrary.internal.d.ts" + } + \ No newline at end of file diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 100081fb8cccf..e9868ed0a6ddc 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -161,6 +161,7 @@ declare namespace ts { GetApplicableRefactors = "getApplicableRefactors", GetEditsForRefactor = "getEditsForRefactor", GetMoveToRefactoringFileSuggestions = "getMoveToRefactoringFileSuggestions", + GetPostPasteImportFixes = "getPostPasteImportFixes", OrganizeImports = "organizeImports", GetEditsForFileRename = "getEditsForFileRename", ConfigurePlugin = "configurePlugin", @@ -545,6 +546,26 @@ declare namespace ts { files: string[]; }; } + /** + * Request refactorings at a given position post pasting text from some other location. + */ + interface GetPostPasteImportFixesRequest extends Request { + command: CommandTypes.GetPostPasteImportFixes; + arguments: GetPostPasteImportFixesRequestArgs; + } + type GetPostPasteImportFixesRequestArgs = FileRequestArgs & { + pastes: { + text: string; + range: TextSpan; + }[]; + copySpan?: FileSpan; + }; + interface GetPostPasteImportFixesResponse extends Response { + body: PostPasteImportAction; + } + interface PostPasteImportAction { + edits: FileCodeEdits[]; + } /** * A set of one or more available refactoring actions, grouped under a parent refactoring. */ @@ -4100,6 +4121,7 @@ declare namespace ts { private getApplicableRefactors; private getEditsForRefactor; private getMoveToRefactoringFileSuggestions; + private getPostPasteImportFixes; private organizeImports; private getEditsForFileRename; private getCodeFixes; @@ -4108,6 +4130,7 @@ declare namespace ts { private getStartAndEndPosition; private mapCodeAction; private mapCodeFixAction; + private mapPostPasteAction; private mapTextChangesToCodeEdits; private mapTextChangeToCodeEdit; private convertTextChangeToCodeEdit; @@ -10398,6 +10421,33 @@ declare namespace ts { readDirectory(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[] | undefined, depth?: number): string[]; } } + namespace codefix { + function getImportFixes(exportInfos: readonly SymbolExportInfo[], usagePosition: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, program: Program, sourceFile: SourceFile, host: LanguageServiceHost, preferences: UserPreferences, importMap?: { + getImportsForExportInfo: ({ moduleSymbol, exportKind, targetFlags, symbol }: SymbolExportInfo) => readonly FixAddToExistingImportInfo[]; + }, fromCacheOnly?: boolean): { + computedWithoutCacheCount: number; + fixes: readonly ImportFixWithModuleSpecifier[]; + }; + function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean; + function sortFixInfo( + fixes: readonly (FixInfo & { + fix: ImportFixWithModuleSpecifier; + })[], + sourceFile: SourceFile, + program: Program, + packageJsonImportFilter: PackageJsonImportFilter, + host: LanguageServiceHost, + ): readonly (FixInfo & { + fix: ImportFixWithModuleSpecifier; + })[]; + type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; + interface FixInfo { + readonly fix: ImportFix; + readonly symbolName: string; + readonly errorIdentifierText: string | undefined; + readonly isJsxNamespaceFix?: boolean; + } + } function getDefaultFormatCodeSettings(newLineCharacter?: string): FormatCodeSettings; /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the @@ -10672,6 +10722,26 @@ declare namespace ts { uncommentSelection(fileName: string, textRange: TextRange): TextChange[]; getSupportedCodeFixes(fileName?: string): readonly string[]; dispose(): void; + getPostPasteImportFixes( + targetFile: string, + pastes: { + text: string; + range: TextRange; + }[], + preferences: UserPreferences, + formatOptions: FormatCodeSettings, + copySpan?: { + file: string; + start: { + line: number; + offset: number; + }; + end: { + line: number; + offset: number; + }; + }, + ): PostPasteImportFixes; } interface JsxClosingTagInfo { readonly newText: string; @@ -10689,6 +10759,9 @@ declare namespace ts { SortAndCombine = "SortAndCombine", RemoveUnused = "RemoveUnused", } + interface PostPasteImportFixes { + edits: readonly FileTextChanges[]; + } interface OrganizeImportsArgs extends CombinedCodeFixScope { /** @deprecated Use `mode` instead */ skipDestructiveCodeActions?: boolean; diff --git a/tests/baselines/reference/tsserver/getPostPasteImportFixes/Returns-the-same-file-unchanged-.js b/tests/baselines/reference/tsserver/getPostPasteImportFixes/Returns-the-same-file-unchanged-.js new file mode 100644 index 0000000000000..c74eca0d1f6e0 --- /dev/null +++ b/tests/baselines/reference/tsserver/getPostPasteImportFixes/Returns-the-same-file-unchanged-.js @@ -0,0 +1,203 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +Before request +//// [/project/a/target.ts] +const a = 1; +const b = 2; +const c = 3; + +//// [/project/tsconfig.json] +{} + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "/project/a/target.ts" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: /project/a +Info seq [hh:mm:ss:mss] For info: /project/a/target.ts :: Config file name: /project/tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /project/tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/tsconfig.json 2000 undefined Project: /project/tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/project/tsconfig.json", + "reason": "Creating possible configured project for /project/a/target.ts to open" + } + } +Info seq [hh:mm:ss:mss] Config: /project/tsconfig.json : { + "rootNames": [ + "/project/a/target.ts" + ], + "options": { + "configFilePath": "/project/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project 1 undefined Config: /project/tsconfig.json WatchType: Wild card directory +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project 1 undefined Config: /project/tsconfig.json WatchType: Wild card directory +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /project/tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /project/tsconfig.json WatchType: Missing file +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (1) + /project/a/target.ts SVC-1-0 "const a = 1;\nconst b = 2;\nconst c = 3;" + + + a/target.ts + Matched by default include pattern '**/*' + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/project/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "telemetry", + "body": { + "telemetryEventName": "projectInfo", + "payload": { + "projectId": "4877b582a3e7d5836ee46b4a0db488dc715db827bacc8ef1fbcd0dbb78ae23d1", + "fileStats": { + "js": 0, + "jsSize": 0, + "jsx": 0, + "jsxSize": 0, + "ts": 1, + "tsSize": 38, + "tsx": 0, + "tsxSize": 0, + "dts": 0, + "dtsSize": 0, + "deferred": 0, + "deferredSize": 0 + }, + "compilerOptions": {}, + "typeAcquisition": { + "enable": false, + "include": false, + "exclude": false + }, + "extends": false, + "files": false, + "include": false, + "exclude": false, + "compileOnSave": false, + "configFileName": "tsconfig.json", + "projectType": "configured", + "languageServiceEnabled": true, + "version": "FakeVersion" + } + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/project/a/target.ts", + "configFile": "/project/tsconfig.json", + "diagnostics": [ + { + "text": "File '/a/lib/lib.d.ts' not found.\n The file is in the program because:\n Default library for target 'es5'", + "code": 6053, + "category": "error" + }, + { + "text": "Cannot find global type 'Array'.", + "code": 2318, + "category": "error" + }, + { + "text": "Cannot find global type 'Boolean'.", + "code": 2318, + "category": "error" + }, + { + "text": "Cannot find global type 'Function'.", + "code": 2318, + "category": "error" + }, + { + "text": "Cannot find global type 'IArguments'.", + "code": 2318, + "category": "error" + }, + { + "text": "Cannot find global type 'Number'.", + "code": 2318, + "category": "error" + }, + { + "text": "Cannot find global type 'Object'.", + "code": 2318, + "category": "error" + }, + { + "text": "Cannot find global type 'RegExp'.", + "code": 2318, + "category": "error" + }, + { + "text": "Cannot find global type 'String'.", + "code": 2318, + "category": "error" + } + ] + } + } +Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (1) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /project/a/target.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /project/tsconfig.json +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +PolledWatches:: +/a/lib/lib.d.ts: *new* + {"pollingInterval":500} + +FsWatches:: +/project/tsconfig.json: *new* + {} + +FsWatchesRecursive:: +/project: *new* + {} + +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /project/tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (1) + /project/a/target.ts SVC-1-1 "const a = 1;\nfunction e();\nconst f = r + s;\nconst b = 2;\nconst c = 3;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /project/tsconfig.json +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (1) + /project/a/target.ts SVC-1-2 "const a = 1;\nconst b = 2;\nconst c = 3;" + +Info seq [hh:mm:ss:mss] ----------------------------------------------- \ No newline at end of file From 9ef3d85d5453399b2d45973352c814c021c4922b Mon Sep 17 00:00:00 2001 From: navya9singh Date: Mon, 12 Feb 2024 12:15:40 -0800 Subject: [PATCH 11/18] Minor fixes --- src/server/session.ts | 3 +- src/services/codefixes/importFixes.ts | 10 ++-- src/services/services.ts | 3 +- .../reference/APILibCheck.errors.txt | 47 ------------------- tests/baselines/reference/api/typescript.d.ts | 27 ----------- 5 files changed, 7 insertions(+), 83 deletions(-) delete mode 100644 tests/baselines/reference/APILibCheck.errors.txt diff --git a/src/server/session.ts b/src/server/session.ts index 050323155381c..c7811dd2d47ca 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2804,8 +2804,7 @@ export class Session implements EventSender { if (result === undefined) { return undefined; } - const allResults = this.mapPostPasteAction(result); - return allResults; + return this.mapPostPasteAction(result); } private organizeImports(args: protocol.OrganizeImportsRequestArgs, simplifiedResult: boolean): readonly protocol.FileCodeEdits[] | readonly FileTextChanges[] { diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index ce2ee8c6ea3ed..b785f68b6671b 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -481,7 +481,7 @@ const enum AddAsTypeOnly { NotAllowed = 1 << 2, } type ImportFix = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport | FixPromoteTypeOnlyImport; -export type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; +type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; // Properties are be undefined if fix is derived from an existing import interface ImportFixBase { @@ -633,7 +633,7 @@ function getSingleExportInfoForSymbol(symbol: Symbol, symbolName: string, module } } -export function getImportFixes( +function getImportFixes( exportInfos: readonly SymbolExportInfo[], usagePosition: number | undefined, isValidTypeOnlyUseSite: boolean, @@ -840,7 +840,7 @@ function createExistingImportMap(checker: TypeChecker, importingFile: SourceFile }; } -export function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean { +function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean { // 1. TypeScript files don't use require variable declarations if (!isSourceFileJS(sourceFile)) { return false; @@ -981,7 +981,7 @@ function newImportInfoFromExistingSpecifier( } } -export interface FixInfo { +interface FixInfo { readonly fix: ImportFix; readonly symbolName: string; readonly errorIdentifierText: string | undefined; @@ -1009,7 +1009,7 @@ function getFixInfos(context: CodeFixContextBase, errorCode: number, pos: number return info && sortFixInfo(info, context.sourceFile, context.program, packageJsonImportFilter, context.host); } -export function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] { +function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] { const _toPath = (fileName: string) => toPath(fileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host)); return sort(fixes, (a, b) => compareBooleans(!!a.isJsxNamespaceFix, !!b.isJsxNamespaceFix) || diff --git a/src/services/services.ts b/src/services/services.ts index d0bdc5ba92946..876ea3bc496b1 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2100,8 +2100,7 @@ export function createLanguageService( ): PostPasteImportFixes { synchronizeHostData(); const originalSourceFile = copySpan ? getValidSourceFile(copySpan.file) : undefined; - const edits = postPasteImportFixes.postPasteImportFixesProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host), cancellationToken, originalSourceFile, copySpan); - return edits; + return postPasteImportFixes.postPasteImportFixesProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host), cancellationToken, originalSourceFile, copySpan); } function getNodeForQuickInfo(node: Node): Node { diff --git a/tests/baselines/reference/APILibCheck.errors.txt b/tests/baselines/reference/APILibCheck.errors.txt deleted file mode 100644 index b81eac4cd40b5..0000000000000 --- a/tests/baselines/reference/APILibCheck.errors.txt +++ /dev/null @@ -1,47 +0,0 @@ -typescript.d.ts(10425,55): error TS2304: Cannot find name 'SymbolExportInfo'. -typescript.d.ts(10426,90): error TS2304: Cannot find name 'SymbolExportInfo'. -typescript.d.ts(10426,120): error TS2304: Cannot find name 'FixAddToExistingImportInfo'. -typescript.d.ts(10438,38): error TS2304: Cannot find name 'PackageJsonImportFilter'. -typescript.d.ts(10443,45): error TS2552: Cannot find name 'FixUseNamespaceImport'. Did you mean 'NamespaceImport'? -typescript.d.ts(10443,69): error TS2304: Cannot find name 'FixAddJsdocTypeImport'. -typescript.d.ts(10443,93): error TS2304: Cannot find name 'FixAddToExistingImport'. -typescript.d.ts(10443,118): error TS2304: Cannot find name 'FixAddNewImport'. -typescript.d.ts(10445,27): error TS2304: Cannot find name 'ImportFix'. -typescript.internal.d.ts(25311,120): error TS2304: Cannot find name 'FixAddToExistingImportInfo'. -typescript.internal.d.ts(25365,45): error TS2304: Cannot find name 'FixUseNamespaceImport'. -typescript.internal.d.ts(25365,69): error TS2304: Cannot find name 'FixAddJsdocTypeImport'. -typescript.internal.d.ts(25365,93): error TS2304: Cannot find name 'FixAddToExistingImport'. -typescript.internal.d.ts(25365,118): error TS2304: Cannot find name 'FixAddNewImport'. -typescript.internal.d.ts(25367,27): error TS2304: Cannot find name 'ImportFix'. - - -==== index.ts (0 errors) ==== - import ts = require("typescript"); - import tsInternal = require("typescript-internal"); - import tsserverlibrary = require("tsserverlibrary"); - import tsserverlibraryInternal = require("tsserverlibrary-internal"); - -==== node_modules/typescript/package.json (0 errors) ==== - { - "name": "typescript", - "types": "/.ts/typescript.d.ts" - } - -==== node_modules/typescript-internal/package.json (0 errors) ==== - { - "name": "typescript-internal", - "types": "/.ts/typescript.internal.d.ts" - } - -==== node_modules/tsserverlibrary/package.json (0 errors) ==== - { - "name": "tsserverlibrary", - "types": "/.ts/tsserverlibrary.d.ts" - } - -==== node_modules/tsserverlibrary-internal/package.json (0 errors) ==== - { - "name": "tsserverlibrary-internal", - "types": "/.ts/tsserverlibrary.internal.d.ts" - } - \ No newline at end of file diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index e9868ed0a6ddc..3b1eb21d70971 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -10421,33 +10421,6 @@ declare namespace ts { readDirectory(rootDir: string, extensions: readonly string[], excludes: readonly string[] | undefined, includes: readonly string[] | undefined, depth?: number): string[]; } } - namespace codefix { - function getImportFixes(exportInfos: readonly SymbolExportInfo[], usagePosition: number | undefined, isValidTypeOnlyUseSite: boolean, useRequire: boolean, program: Program, sourceFile: SourceFile, host: LanguageServiceHost, preferences: UserPreferences, importMap?: { - getImportsForExportInfo: ({ moduleSymbol, exportKind, targetFlags, symbol }: SymbolExportInfo) => readonly FixAddToExistingImportInfo[]; - }, fromCacheOnly?: boolean): { - computedWithoutCacheCount: number; - fixes: readonly ImportFixWithModuleSpecifier[]; - }; - function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean; - function sortFixInfo( - fixes: readonly (FixInfo & { - fix: ImportFixWithModuleSpecifier; - })[], - sourceFile: SourceFile, - program: Program, - packageJsonImportFilter: PackageJsonImportFilter, - host: LanguageServiceHost, - ): readonly (FixInfo & { - fix: ImportFixWithModuleSpecifier; - })[]; - type ImportFixWithModuleSpecifier = FixUseNamespaceImport | FixAddJsdocTypeImport | FixAddToExistingImport | FixAddNewImport; - interface FixInfo { - readonly fix: ImportFix; - readonly symbolName: string; - readonly errorIdentifierText: string | undefined; - readonly isJsxNamespaceFix?: boolean; - } - } function getDefaultFormatCodeSettings(newLineCharacter?: string): FormatCodeSettings; /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the From 7f41f3098f361a57c763775937a35c544fced3b0 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Mon, 12 Feb 2024 15:41:16 -0800 Subject: [PATCH 12/18] Fixing baselines --- .../postPasteImportFixes_existingImports1.js | 78 ++++++++++++++++- .../postPasteImportFixes_existingImports2.js | 86 ++++++++++++++++++- .../postPasteImportFixes_knownSourceFile.js | 70 ++++++++++++++- .../postPasteImportFixes_multiplePastes1.js | 70 ++++++++++++++- .../postPasteImportFixes_multiplePastes2.js | 70 ++++++++++++++- .../postPasteImportFixes_pasteComments.js | 54 +++++++++++- .../postPasteImportFixes_unknownSourceFile.js | 62 ++++++++++++- .../Returns-the-same-file-unchanged-.js | 17 +++- 8 files changed, 476 insertions(+), 31 deletions(-) diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js index 8477babc0f4b3..b1045e92c98af 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js @@ -70,7 +70,7 @@ Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (7) /lib.d.ts Text-1 lib.d.ts-Text @@ -144,6 +144,41 @@ watchedFiles:: /tsconfig.json: *new* {"pollingInterval":2000} +Projects:: +/tsconfig.json (Configured) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/lib.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other2.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other3.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /tsconfig.json *default* + Info seq [hh:mm:ss:mss] request: { "seq": 1, @@ -210,7 +245,7 @@ Info seq [hh:mm:ss:mss] request: "command": "getPostPasteImportFixes" } Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (7) /lib.d.ts Text-1 lib.d.ts-Text @@ -223,7 +258,7 @@ Info seq [hh:mm:ss:mss] Files (7) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 3 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (7) /lib.d.ts Text-1 lib.d.ts-Text @@ -276,4 +311,39 @@ Info seq [hh:mm:ss:mss] response: } ] } - } \ No newline at end of file + } +After Request +Projects:: +/tsconfig.json (Configured) *changed* + projectStateVersion: 3 *changed* + projectProgramVersion: 1 + +ScriptInfos:: +/lib.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other2.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other3.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *changed* + version: SVC-1-2 *changed* + containingProjects: 1 + /tsconfig.json *default* diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js index 8b9854f9637de..a821cde26a378 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js @@ -78,7 +78,7 @@ Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (8) /lib.d.ts Text-1 lib.d.ts-Text @@ -159,6 +159,45 @@ watchedFiles:: /tsconfig.json: *new* {"pollingInterval":2000} +Projects:: +/tsconfig.json (Configured) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/lib.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/originalFile.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other2.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other3.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /tsconfig.json *default* + Info seq [hh:mm:ss:mss] request: { "seq": 1, @@ -236,7 +275,7 @@ Info seq [hh:mm:ss:mss] request: "command": "getPostPasteImportFixes" } Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (8) /lib.d.ts Text-1 lib.d.ts-Text @@ -252,7 +291,7 @@ Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 3 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (8) /lib.d.ts Text-1 lib.d.ts-Text @@ -317,4 +356,43 @@ Info seq [hh:mm:ss:mss] response: } ] } - } \ No newline at end of file + } +After Request +Projects:: +/tsconfig.json (Configured) *changed* + projectStateVersion: 3 *changed* + projectProgramVersion: 1 + +ScriptInfos:: +/lib.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/originalFile.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other2.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other3.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *changed* + version: SVC-1-2 *changed* + containingProjects: 1 + /tsconfig.json *default* diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js index 60fb7ede7b610..5bc51ef0860f4 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js @@ -66,7 +66,7 @@ Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -134,6 +134,37 @@ watchedFiles:: /tsconfig.json: *new* {"pollingInterval":2000} +Projects:: +/tsconfig.json (Configured) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/file1.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/file2.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /tsconfig.json *default* + Info seq [hh:mm:ss:mss] request: { "seq": 1, @@ -211,7 +242,7 @@ Info seq [hh:mm:ss:mss] request: "command": "getPostPasteImportFixes" } Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -225,7 +256,7 @@ Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 3 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -304,4 +335,35 @@ Info seq [hh:mm:ss:mss] response: } ] } - } \ No newline at end of file + } +After Request +Projects:: +/tsconfig.json (Configured) *changed* + projectStateVersion: 3 *changed* + projectProgramVersion: 1 + +ScriptInfos:: +/file1.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/file2.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *changed* + version: SVC-1-2 *changed* + containingProjects: 1 + /tsconfig.json *default* diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js index 727d587a6636e..ab8f2527e700b 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js @@ -68,7 +68,7 @@ Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -135,6 +135,37 @@ watchedFiles:: /tsconfig.json: *new* {"pollingInterval":2000} +Projects:: +/tsconfig.json (Configured) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/file1.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/file3.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /tsconfig.json *default* + Info seq [hh:mm:ss:mss] request: { "seq": 1, @@ -214,7 +245,7 @@ Info seq [hh:mm:ss:mss] request: "command": "getPostPasteImportFixes" } Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -226,7 +257,7 @@ Info seq [hh:mm:ss:mss] Files (6) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 3 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -289,4 +320,35 @@ Info seq [hh:mm:ss:mss] response: } ] } - } \ No newline at end of file + } +After Request +Projects:: +/tsconfig.json (Configured) *changed* + projectStateVersion: 3 *changed* + projectProgramVersion: 1 + +ScriptInfos:: +/file1.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/file3.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *changed* + version: SVC-1-2 *changed* + containingProjects: 1 + /tsconfig.json *default* diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js index abd684c7c5130..56cfa5f0d74a3 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js @@ -70,7 +70,7 @@ Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -138,6 +138,37 @@ watchedFiles:: /tsconfig.json: *new* {"pollingInterval":2000} +Projects:: +/tsconfig.json (Configured) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/file1.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /tsconfig.json *default* + Info seq [hh:mm:ss:mss] request: { "seq": 1, @@ -228,7 +259,7 @@ Info seq [hh:mm:ss:mss] request: "command": "getPostPasteImportFixes" } Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -243,7 +274,7 @@ Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms Info seq [hh:mm:ss:mss] getExportInfoMap: cache hit Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 3 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (6) /lib.d.ts Text-1 lib.d.ts-Text @@ -317,4 +348,35 @@ Info seq [hh:mm:ss:mss] response: } ] } - } \ No newline at end of file + } +After Request +Projects:: +/tsconfig.json (Configured) *changed* + projectStateVersion: 3 *changed* + projectProgramVersion: 1 + +ScriptInfos:: +/file1.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/other.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *changed* + version: SVC-1-2 *changed* + containingProjects: 1 + /tsconfig.json *default* diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js index c6cb16bb03451..6bca87a4addb3 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js @@ -53,7 +53,7 @@ Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (4) /lib.d.ts Text-1 lib.d.ts-Text @@ -110,6 +110,29 @@ watchedFiles:: /tsconfig.json: *new* {"pollingInterval":2000} +Projects:: +/tsconfig.json (Configured) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/lib.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /tsconfig.json *default* + Info seq [hh:mm:ss:mss] request: { "seq": 1, @@ -176,7 +199,7 @@ Info seq [hh:mm:ss:mss] request: "command": "getPostPasteImportFixes" } Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (4) /lib.d.ts Text-1 lib.d.ts-Text @@ -186,7 +209,7 @@ Info seq [hh:mm:ss:mss] Files (4) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 3 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (4) /lib.d.ts Text-1 lib.d.ts-Text @@ -225,4 +248,27 @@ Info seq [hh:mm:ss:mss] response: } ] } - } \ No newline at end of file + } +After Request +Projects:: +/tsconfig.json (Configured) *changed* + projectStateVersion: 3 *changed* + projectProgramVersion: 1 + +ScriptInfos:: +/lib.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/target.ts (Open) *changed* + version: SVC-1-2 *changed* + containingProjects: 1 + /tsconfig.json *default* diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js index ddc26b007de3e..596ea7611195c 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js @@ -61,7 +61,7 @@ Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (5) /lib.d.ts Text-1 lib.d.ts-Text @@ -123,6 +123,33 @@ watchedFiles:: /tsconfig.json: *new* {"pollingInterval":2000} +Projects:: +/tsconfig.json (Configured) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/file1.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/file2.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /tsconfig.json *default* +/lib.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts *new* + version: Text-1 + containingProjects: 1 + /tsconfig.json + Info seq [hh:mm:ss:mss] request: { "seq": 1, @@ -189,7 +216,7 @@ Info seq [hh:mm:ss:mss] request: "command": "getPostPasteImportFixes" } Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (5) /lib.d.ts Text-1 lib.d.ts-Text @@ -200,7 +227,7 @@ Info seq [hh:mm:ss:mss] Files (5) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /tsconfig.json projectStateVersion: 3 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (5) /lib.d.ts Text-1 lib.d.ts-Text @@ -251,4 +278,31 @@ Info seq [hh:mm:ss:mss] response: } ] } - } \ No newline at end of file + } +After Request +Projects:: +/tsconfig.json (Configured) *changed* + projectStateVersion: 3 *changed* + projectProgramVersion: 1 + +ScriptInfos:: +/file1.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/file2.ts (Open) *changed* + version: SVC-1-2 *changed* + containingProjects: 1 + /tsconfig.json *default* +/lib.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json +/lib.decorators.legacy.d.ts + version: Text-1 + containingProjects: 1 + /tsconfig.json diff --git a/tests/baselines/reference/tsserver/getPostPasteImportFixes/Returns-the-same-file-unchanged-.js b/tests/baselines/reference/tsserver/getPostPasteImportFixes/Returns-the-same-file-unchanged-.js index c74eca0d1f6e0..cd4e9f43ba699 100644 --- a/tests/baselines/reference/tsserver/getPostPasteImportFixes/Returns-the-same-file-unchanged-.js +++ b/tests/baselines/reference/tsserver/getPostPasteImportFixes/Returns-the-same-file-unchanged-.js @@ -45,7 +45,7 @@ Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project 1 undefi Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project 1 undefined Config: /project/tsconfig.json WatchType: Wild card directory Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /project/tsconfig.json Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /project/tsconfig.json WatchType: Missing file -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (1) /project/a/target.ts SVC-1-0 "const a = 1;\nconst b = 2;\nconst c = 3;" @@ -187,15 +187,26 @@ FsWatchesRecursive:: /project: *new* {} +Projects:: +/project/tsconfig.json (Configured) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/project/a/target.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /project/tsconfig.json *default* + Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /project/tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json Version: 2 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json projectStateVersion: 2 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (1) /project/a/target.ts SVC-1-1 "const a = 1;\nfunction e();\nconst f = r + s;\nconst b = 2;\nconst c = 3;" Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /project/tsconfig.json -Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json Version: 3 structureChanged: false structureIsReused:: Completely Elapsed:: *ms +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/tsconfig.json projectStateVersion: 3 projectProgramVersion: 1 structureChanged: false structureIsReused:: Completely Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/project/tsconfig.json' (Configured) Info seq [hh:mm:ss:mss] Files (1) /project/a/target.ts SVC-1-2 "const a = 1;\nconst b = 2;\nconst c = 3;" From d3816d3ac2c042e0f1bea8956b2854de8d6c8c07 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Mon, 19 Feb 2024 21:54:34 -0800 Subject: [PATCH 13/18] changes based on reviews 1 --- src/harness/client.ts | 11 +++--- src/harness/fourslashImpl.ts | 2 +- src/harness/fourslashInterfaceImpl.ts | 9 ++--- src/server/project.ts | 5 ++- src/server/protocol.ts | 9 +++-- src/server/session.ts | 11 +++++- src/services/codefixes/importFixes.ts | 4 +- src/services/postPasteImportFixes.ts | 39 +++++++++++-------- src/services/services.ts | 15 +++++-- src/services/types.ts | 6 +-- .../tsserver/postPasteImportFixes.ts | 2 +- tests/cases/fourslash/fourslash.ts | 8 +--- .../postPasteImportFixes_existingImports1.ts | 6 +-- .../postPasteImportFixes_existingImports2.ts | 11 ++---- .../postPasteImportFixes_knownSourceFile.ts | 11 +++--- .../postPasteImportFixes_multiplePastes1.ts | 11 +----- .../postPasteImportFixes_multiplePastes2.ts | 18 +++------ .../postPasteImportFixes_pasteComments.ts | 6 +-- .../postPasteImportFixes_unknownSourceFile.ts | 4 +- 19 files changed, 93 insertions(+), 95 deletions(-) diff --git a/src/harness/client.ts b/src/harness/client.ts index 1e022eb7be7f6..90ba9dbf76459 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -1,6 +1,5 @@ import { ApplicableRefactorInfo, - arrayFrom, CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, @@ -1013,15 +1012,15 @@ export class SessionClient implements LanguageService { getPostPasteImportFixes( targetFile: string, - pastes: { text: string; range: TextRange; }[], + copies: { text: string; copyRange?: { file: string; range: TextRange;} }[], + pastes: TextRange[], _preferences: UserPreferences, - _formatOptions: FormatCodeSettings, - copySpan?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, + _formatOptions: FormatCodeSettings ): PostPasteImportFixes { const args: protocol.GetPostPasteImportFixesRequestArgs = { file: targetFile, - pastes: arrayFrom(pastes.map(paste => ({ text: paste.text, range: { start: this.positionToOneBasedLineOffset(targetFile, paste.range.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.range.end) } }))), - copySpan, + copies: copies.map(copy => ({ text: copy.text, range: copy.copyRange ? { file: copy.copyRange.file, start: this.positionToOneBasedLineOffset(copy.copyRange.file, copy.copyRange.range.pos), end: this.positionToOneBasedLineOffset(copy.copyRange.file, copy.copyRange.range.end) } : undefined })), + pastes: pastes.map(paste => ({ start: this.positionToOneBasedLineOffset(targetFile, paste.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.end) })), }; const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); const response = this.processResponse(request); diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index f6c6aaa316ad5..ea10010e21971 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -3563,7 +3563,7 @@ export class TestState { } public verifyPostPasteImportFixes(options: FourSlashInterface.PostPasteImportFixOptions): void { - const editInfo = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, options.pastes, options.preferences, this.formatCodeSettings, options.copySpan); + const editInfo = this.languageService.getPostPasteImportFixes(this.activeFile.fileName, options.copies, options.pastes, options.preferences, this.formatCodeSettings); this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits); } diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index b6a7e5b76ead4..744c1cbdb4b3c 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1,6 +1,3 @@ -import { - Location, -} from "../server/protocol"; import * as FourSlash from "./_namespaces/FourSlash"; import * as ts from "./_namespaces/ts"; @@ -1889,8 +1886,8 @@ export interface VerifyCodeFixAllOptions { export interface VerifyPostPasteImportFix { targetFile: string; pastes: { text: string; range: ts.TextRange; }[]; + copySpan?: { file: string; range: ts.TextRange; }; preferences: ts.UserPreferences; - copySpan?: { file: string; start: Location; end: Location; }; } export interface VerifyRefactorOptions { @@ -1935,9 +1932,9 @@ export interface MoveToFileOptions { export interface PostPasteImportFixOptions { readonly newFileContents: { readonly [fileName: string]: string; }; - readonly pastes: { text: string; range: ts.TextRange; }[]; + readonly copies: { text: string; copyRange?: { file: string; range: ts.TextRange;} }[], + readonly pastes: ts.TextRange[], readonly preferences: ts.UserPreferences; - readonly copySpan?: { file: string; start: Location; end: Location; }; } export type RenameLocationsOptions = readonly RenameLocationOptions[] | { diff --git a/src/server/project.ts b/src/server/project.ts index 555bbdb9091e2..c3a4ae7616cbf 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2216,9 +2216,10 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - updateTargetFile(rootFile: string, targetFileText: string, pastedText: string): { updatedFile: SourceFile | undefined; updatedProgram: Program | undefined; originalProgram: ts.Program | undefined; } { + runWithTemporaryFileUpdate(rootFile: string, pastedText: string): { updatedFile: SourceFile | undefined; updatedProgram: Program | undefined; originalProgram: ts.Program | undefined; } { const originalProgram = this.program; - this.getScriptInfo(rootFile)?.editContent(0, targetFileText.length, pastedText); + Debug.assert(this.program && this.program.getSourceFile(rootFile)); + this.getScriptInfo(rootFile)?.editContent(0, this.program.getSourceFile(rootFile)!.getText().length, pastedText); this.updateGraph(); return { updatedFile: (this.program?.getSourceFile(rootFile)), updatedProgram: this.program, originalProgram }; } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 7f6fee9920b13..76967b4fc6ac1 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -641,9 +641,12 @@ export interface GetPostPasteImportFixesRequest extends Request { } export type GetPostPasteImportFixesRequestArgs = FileRequestArgs & { - pastes: { text: string; range: TextSpan; }[]; - copySpan?: FileSpan; -}; + copies: { + text: string; + range?: FileSpan; + }[]; + pastes: TextSpan[]; + }; export interface GetPostPasteImportFixesResponse extends Response { body: PostPasteImportAction; } diff --git a/src/server/session.ts b/src/server/session.ts index a9b5f1196d519..e0e151958a2d0 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2799,8 +2799,15 @@ export class Session implements EventSender { private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction | undefined { const { file, project } = this.getFileAndProject(args); - const pastes = arrayFrom(args.pastes).map(paste => ({ text: paste.text, range: this.getRange({ file, startLine: paste.range.start.line, startOffset: paste.range.start.offset, endLine: paste.range.end.line, endOffset: paste.range.end.offset }, project.getScriptInfoForNormalizedPath(file)!) })); - const result = project.getLanguageService().getPostPasteImportFixes(file, pastes, this.getPreferences(file), this.getFormatOptions(file), args.copySpan); + //const pastes = args.pastes.map(paste => ({ text: paste.text, range: this.getRange({ file, startLine: paste.range.start.line, startOffset: paste.range.start.offset, endLine: paste.range.end.line, endOffset: paste.range.end.offset }, project.getScriptInfoForNormalizedPath(file)!) })); + //const pastes = args.pastes.map(paste => this.getRange({ file, startLine: paste.start.line, startOffset: paste.start.offset, endLine: paste.end.line, endOffset: paste.end.offset }, project.getScriptInfoForNormalizedPath(file)!)); + const copyFile = args.copies[0].range ? args.copies[0].range.file : undefined; + const result = project.getLanguageService().getPostPasteImportFixes( + file, + args.copies.map(copy => ({ text: copy.text, copyRange: copy.range && copyFile ? { file: copy.range.file, range: this.getRange({ file: copyFile, startLine: copy.range.start.line, startOffset: copy.range.start.offset, endLine: copy.range.end.line, endOffset: copy.range.end.offset }, project.getScriptInfoForNormalizedPath(toNormalizedPath(copyFile))!) }: undefined })), + args.pastes.map(paste => this.getRange({ file, startLine: paste.start.line, startOffset: paste.start.offset, endLine: paste.end.line, endOffset: paste.end.offset }, project.getScriptInfoForNormalizedPath(file)!)), + this.getPreferences(file), + this.getFormatOptions(file)); if (result === undefined) { return undefined; } diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 98de7dac81d99..9980d418fa7a1 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -210,8 +210,8 @@ export interface ImportAdder { hasFixes(): boolean; addImportFromDiagnostic: (diagnostic: DiagnosticWithLocation, context: CodeFixContextBase) => void; addImportFromExportedSymbol: (exportedSymbol: Symbol, isValidTypeOnlyUseSite?: boolean) => void; + addImportForUnresolvedIdentifier: (context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean) => void; writeFixes: (changeTracker: textChanges.ChangeTracker, oldFileQuotePreference?: QuotePreference) => void; - addImportsForUnknownSymbols: (context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean) => void; } /** @internal */ @@ -236,7 +236,7 @@ function createImportAdderWorker(sourceFile: SourceFile, program: Program, useAu type NewImportsKey = `${0 | 1}|${string}`; /** Use `getNewImportEntry` for access */ const newImports = new Map>(); - return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes, addImportsForUnknownSymbols }; + return { addImportFromDiagnostic, addImportFromExportedSymbol, writeFixes, hasFixes, addImportForUnresolvedIdentifier: addImportsForUnknownSymbols }; function addImportsForUnknownSymbols(context: CodeFixContextBase, symbolToken: Identifier, useAutoImportProvider: boolean) { const info = getFixInfosWithoutDiagnostic(context, symbolToken, useAutoImportProvider); diff --git a/src/services/postPasteImportFixes.ts b/src/services/postPasteImportFixes.ts index 220369ae1cc8c..0030b727d94de 100644 --- a/src/services/postPasteImportFixes.ts +++ b/src/services/postPasteImportFixes.ts @@ -16,6 +16,7 @@ import { UserPreferences, } from "../compiler/types"; import { + getLineOfLocalPosition, hasSyntacticModifier, skipAlias, } from "../compiler/utilities"; @@ -55,44 +56,47 @@ import { /** @internal */ export function postPasteImportFixesProvider( targetFile: SourceFile, + //pastes: { text: string; range: TextRange; }[], + copies: { text: string; copyRange?: { file: SourceFile; range: TextRange;} }[], + pastes: TextRange[], host: LanguageServiceHost, - pastes: { text: string; range: TextRange; }[], preferences: UserPreferences, formatContext: formatting.FormatContext, cancellationToken: CancellationToken, - originalFile?: SourceFile, - copyLocation?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, + //originalFile?: SourceFile, + //copyLocation?: { file: string; range: TextRange; }, ): PostPasteImportFixes { - const changes: FileTextChanges[] = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => postPasteFixes(targetFile, host, pastes, preferences, formatContext, cancellationToken, changeTracker, originalFile, copyLocation)); - + const changes: FileTextChanges[] = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => postPasteFixes(targetFile, copies, pastes, host, preferences, formatContext, cancellationToken, changeTracker)); return { edits: changes }; } function postPasteFixes( targetFile: SourceFile, + copies: { text: string; copyRange?: { file: SourceFile; range: TextRange;} }[], + pastes: TextRange[], host: LanguageServiceHost, - pastes: { text: string; range: TextRange; }[], preferences: UserPreferences, formatContext: formatting.FormatContext, cancellationToken: CancellationToken, changes: textChanges.ChangeTracker, - originalFile?: SourceFile, - copyLocation?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, ) { - const updatedTargetFile = host.updateTargetFile?.(targetFile.fileName, targetFile.getText(), targetFile.getText().slice(0, pastes[0].range.pos) + pastes[0].text + targetFile.getText().slice(pastes[0].range.end)); + const copy = copies[0]; + const updatedTargetFile = host.runWithTemporaryFileUpdate?.(targetFile.fileName, targetFile.getText().slice(0, pastes[0].pos) + copy.text + targetFile.getText().slice(pastes[0].end)); const statements: Statement[] = []; Debug.assert(updatedTargetFile && updatedTargetFile.updatedFile && updatedTargetFile.originalProgram && updatedTargetFile.updatedProgram); - if (originalFile) { - addRange(statements, originalFile.statements, copyLocation?.start.line, copyLocation ? copyLocation.end.line + 1 : undefined); - const usage = getUsageInfo(originalFile, statements, updatedTargetFile.originalProgram.getTypeChecker(), getExistingLocals(updatedTargetFile.updatedFile, statements, updatedTargetFile.originalProgram.getTypeChecker())); + if (copy.copyRange) { + const _start = getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.pos); + const _end = getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.end); + addRange(statements, copy.copyRange.file.statements, getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.pos), getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.end) + 1); + const usage = getUsageInfo(copy.copyRange.file, statements, updatedTargetFile.originalProgram.getTypeChecker(), getExistingLocals(updatedTargetFile.updatedFile, statements, updatedTargetFile.originalProgram.getTypeChecker())); const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); - const imports = getImportsFromKnownOriginalFile(originalFile, targetFile, updatedTargetFile.updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, preferences, host, updatedTargetFile.originalProgram.getTypeChecker()); + const imports = getImportsFromKnownOriginalFile(copy.copyRange.file, targetFile, updatedTargetFile.updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, preferences, host, updatedTargetFile.originalProgram.getTypeChecker()); if (imports.length > 0) { insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); } - importAdder.writeFixes(changes, getQuotePreference(originalFile, preferences)); + importAdder.writeFixes(changes, getQuotePreference(copy.copyRange.file, preferences)); host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); } else { @@ -109,7 +113,7 @@ function postPasteFixes( if (isIdentifier(node)) { if (!updatedTargetFile.originalProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ false)) { // generate imports - importAdder.addImportsForUnknownSymbols(context, node, /*useAutoImportProvider*/ true); + importAdder.addImportForUnresolvedIdentifier(context, node, /*useAutoImportProvider*/ true); } } else { @@ -119,8 +123,9 @@ function postPasteFixes( importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); } - pastes.forEach(({ text, range }) => { - range.pos === range.end ? changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text) : changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text); + pastes.forEach((paste) => { + changes.replaceRangeWithText(targetFile, { pos: paste.pos, end: paste.end }, copy.text); + //range.pos === range.end ? changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text) : changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text); }); } diff --git a/src/services/services.ts b/src/services/services.ts index 876ea3bc496b1..526caf59ebd85 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2093,14 +2093,21 @@ export function createLanguageService( function getPostPasteImportFixes( targetFile: string, - pastes: { text: string; range: TextRange; }[], + // pastes: { text: string; range: TextRange; }[], + // copySpan: { file: string; range: TextRange; } | undefined, + copies: { text: string; copyRange?: { file: string; range: TextRange;} }[], + pastes: TextRange[], preferences: UserPreferences, formatOptions: FormatCodeSettings, - copySpan?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, ): PostPasteImportFixes { synchronizeHostData(); - const originalSourceFile = copySpan ? getValidSourceFile(copySpan.file) : undefined; - return postPasteImportFixes.postPasteImportFixesProvider(getValidSourceFile(targetFile), host, pastes, preferences, formatting.getFormatContext(formatOptions, host), cancellationToken, originalSourceFile, copySpan); + return postPasteImportFixes.postPasteImportFixesProvider( + getValidSourceFile(targetFile), + copies.map(({ text, copyRange }) => ({ text, copyRange: copyRange ? { file: getValidSourceFile(copyRange.file), range: copyRange.range } : undefined })), + pastes, + host, + preferences, + formatting.getFormatContext(formatOptions, host), cancellationToken); } function getNodeForQuickInfo(node: Node): Node { diff --git a/src/services/types.ts b/src/services/types.ts index 8276d39fca5fd..21af24777c4ad 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -431,7 +431,7 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; /** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; - /** @internal */ updateTargetFile?(rootFile: string, targetFileText: string, pastedText: string): { updatedFile: SourceFile | undefined; updatedProgram: Program | undefined; originalProgram: Program | undefined; }; + /** @internal */ runWithTemporaryFileUpdate?(rootFile: string, pastedText: string): { updatedFile: SourceFile | undefined; updatedProgram: Program | undefined; originalProgram: Program | undefined; }; /** @internal */ revertUpdatedFile?(rootFile: string, updatedText: string, originalText: string): void; jsDocParsingMode?: JSDocParsingMode | undefined; } @@ -687,10 +687,10 @@ export interface LanguageService { dispose(): void; getPostPasteImportFixes( targetFile: string, - pastes: { text: string; range: TextRange; }[], + copies: { text: string; range?: { file: string; range: TextRange;} }[], + pastes: TextRange[], preferences: UserPreferences, formatOptions: FormatCodeSettings, - copySpan?: { file: string; start: { line: number; offset: number; }; end: { line: number; offset: number; }; }, ): PostPasteImportFixes; } diff --git a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts index 6935f487b4d37..765792936db5b 100644 --- a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts +++ b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts @@ -35,7 +35,7 @@ const c = 3;`; const originalProgram = session.getProjectService().configuredProjects.get(tsconfig.path)!.getLanguageService().getProgram(); const hostProject = session.getProjectService().configuredProjects.get(tsconfig.path)!; - const updatedContent = hostProject.updateTargetFile(target.path, target.content, pastedText); + const updatedContent = hostProject.runWithTemporaryFileUpdate(target.path, pastedText); if (updatedContent.updatedFile !== undefined) { hostProject.revertUpdatedFile(target.path, updatedContent.updatedFile.getText(), originalContent); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index e73659845bd61..539e1c15659fd 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -212,10 +212,6 @@ declare namespace FourSlashInterface { start: number; end: number; } - interface Location { - line: number; - offset: number; - } class test_ { markers(): Marker[]; markerNames(): string[]; @@ -450,8 +446,8 @@ declare namespace FourSlashInterface { uncommentSelection(newFileContent: string): void; postPasteImportFixes(options: { newFileContents: { readonly [fileName: string]: string }; - pastes: Array<{ text: string; range: { pos: number, end: number }}>; - copySpan?: { file: string, start: Location, end: Location }, + copies: { text: string; copyRange?: { file: string; range: { pos: number, end: number };} }[], + pastes: { pos: number, end: number }[], }): void; } class edit { diff --git a/tests/cases/fourslash/server/postPasteImportFixes_existingImports1.ts b/tests/cases/fourslash/server/postPasteImportFixes_existingImports1.ts index 82aeef5f7d998..552829ebe6ae3 100644 --- a/tests/cases/fourslash/server/postPasteImportFixes_existingImports1.ts +++ b/tests/cases/fourslash/server/postPasteImportFixes_existingImports1.ts @@ -22,10 +22,8 @@ const range = test.ranges(); format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFixes({ - pastes: [{ - text: `const m = t3 + t2 + 1;`, - range: range[0], - }], + copies: [{ text: `const m = t3 + t2 + 1;`}], + pastes: [{ pos: range[0].pos, end: range[0].end }], newFileContents: { "/target.ts": `import { t } from "./other"; diff --git a/tests/cases/fourslash/server/postPasteImportFixes_existingImports2.ts b/tests/cases/fourslash/server/postPasteImportFixes_existingImports2.ts index 3ad98da93f4cb..6b991fbdc6904 100644 --- a/tests/cases/fourslash/server/postPasteImportFixes_existingImports2.ts +++ b/tests/cases/fourslash/server/postPasteImportFixes_existingImports2.ts @@ -20,7 +20,7 @@ //// import { t2 } from "./other2"; //// import { t3 } from "./other3"; //// export const n = 10; -//// export const m = t3 + t2 + n; +//// [|export const m = t3 + t2 + n;|] // @Filename: /tsconfig.json ////{ "files": ["target.ts", "originalFile.ts", "other.ts", "other2.ts", "other3.ts"] } @@ -28,10 +28,8 @@ const range = test.ranges(); format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFixes({ - pastes: [{ - text: `const m = t3 + t2 + n;`, - range: range[0], - }], + copies: [{ text: `const m = t3 + t2 + n;`, copyRange: { file: "originalFile.ts", range: range[1]}}], + pastes: [range[0]], newFileContents: { "/target.ts": `import { n } from "./originalFile"; @@ -41,6 +39,5 @@ import { t3 } from "./other3"; const a = t + 1; const m = t3 + t2 + n; const c = 10;` - }, - copySpan: { file: "originalFile.ts", start: { line : 3, offset: 0}, end : { line: 3, offset: 30}}, + } }); diff --git a/tests/cases/fourslash/server/postPasteImportFixes_knownSourceFile.ts b/tests/cases/fourslash/server/postPasteImportFixes_knownSourceFile.ts index 97722efb4ea37..a7135d64e53ac 100644 --- a/tests/cases/fourslash/server/postPasteImportFixes_knownSourceFile.ts +++ b/tests/cases/fourslash/server/postPasteImportFixes_knownSourceFile.ts @@ -11,21 +11,22 @@ // @Filename: /file2.ts ////import { b } from './file1'; ////const a = 1; -////const c = a + b; -////const t = 9; +////[|const c = a + b; +////const t = 9;|] // @Filename: /tsconfig.json ////{ "files": ["file1.ts", "file2.ts", "target.ts"] } const range = test.ranges(); +const t = range[0]; format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFixes({ - pastes: [{ + copies: [{ text: `const c = a + b; const t = 9;`, - range: range[0], + copyRange: { file: "file2.ts", range: range[1]} }], - copySpan: { file:"file2.ts", start: { line : 2, offset: 0}, end : { line: 3, offset: 0}}, + pastes: [range[0]], newFileContents: { "/file2.ts": `import { b } from './file1'; diff --git a/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes1.ts b/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes1.ts index bef58f87b1899..ff1c5bf8e5d92 100644 --- a/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes1.ts +++ b/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes1.ts @@ -22,19 +22,12 @@ const range = test.ranges(); format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFixes({ - pastes: [{ + copies: [{ text: `const g = p + q; function e(); const f = r + s;`, - range: range[0], - }, - { - text: `const g = p + q; -function e(); -const f = r + s;`, - range: range[1], - }], + pastes: [range[0], range[1]], newFileContents: { "/target.ts": `import { p, q } from "./file1"; diff --git a/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes2.ts b/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes2.ts index 93ea4de93e5bf..b7838b907fc80 100644 --- a/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes2.ts +++ b/tests/cases/fourslash/server/postPasteImportFixes_multiplePastes2.ts @@ -11,8 +11,8 @@ //// import { aa, bb } from "./other"; //// export const r = 10; //// export const s = 12; -//// export const t = aa + bb + r + s; -//// const u = 1; +//// [|export const t = aa + bb + r + s; +//// const u = 1;|] // @Filename: /other.ts //// export const aa = 1; @@ -24,17 +24,12 @@ const range = test.ranges(); format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFixes({ - pastes: [{ + copies: [{ text: `export const t = aa + bb + r + s; const u = 1;`, - range: range[0], - }, - { - text: `export const t = aa + bb + r + s; -const u = 1;`, - range: range[1], - + copyRange: { file: "file1.ts", range: range[2]} }], + pastes: [range[0], range[1]], newFileContents: { "/target.ts": `import { r, s } from "./file1"; @@ -48,6 +43,5 @@ const c = 3; export const t = aa + bb + r + s; const u = 1; const d = 4;` - }, - copySpan: { file: "file1.ts", start: { line : 3, offset: 0}, end : { line: 4, offset: 12}}, + }, }); \ No newline at end of file diff --git a/tests/cases/fourslash/server/postPasteImportFixes_pasteComments.ts b/tests/cases/fourslash/server/postPasteImportFixes_pasteComments.ts index 60c272e5d9447..71c80fb71acb7 100644 --- a/tests/cases/fourslash/server/postPasteImportFixes_pasteComments.ts +++ b/tests/cases/fourslash/server/postPasteImportFixes_pasteComments.ts @@ -11,15 +11,15 @@ const range = test.ranges(); format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFixes({ - pastes: [{ + copies: [{ text: `/** * Testing comment line 1 * line 2 * line 3 * line 4 -*/`, - range: range[0], +*/` }], + pastes: [range[0]], newFileContents: { "/target.ts": `const a = 10; diff --git a/tests/cases/fourslash/server/postPasteImportFixes_unknownSourceFile.ts b/tests/cases/fourslash/server/postPasteImportFixes_unknownSourceFile.ts index 009d847fdca3c..0da558ec4c045 100644 --- a/tests/cases/fourslash/server/postPasteImportFixes_unknownSourceFile.ts +++ b/tests/cases/fourslash/server/postPasteImportFixes_unknownSourceFile.ts @@ -17,15 +17,15 @@ const range = test.ranges(); format.setOption("insertSpaceAfterSemicolonInForStatements", true); verify.postPasteImportFixes({ - pastes: [{ + copies: [{ text: `interface Testing { test1: Test1; test2: Test2; test3: Test3; test4: Test4; }`, - range: range[0], }], + pastes: [range[0]], newFileContents: { "/file2.ts": `import { Test1, Test2, Test3, Test4 } from "./file1"; From 3914539cc23cf648250383bd2ca510290347592a Mon Sep 17 00:00:00 2001 From: navya9singh Date: Tue, 20 Feb 2024 12:52:48 -0800 Subject: [PATCH 14/18] changes based on review 2 --- src/harness/client.ts | 2 +- src/server/project.ts | 14 +- src/server/session.ts | 5 +- src/services/postPasteImportFixes.ts | 160 ++++-------------- src/services/refactors/moveToFile.ts | 92 +--------- src/services/services.ts | 2 - src/services/types.ts | 3 +- src/services/utilities.ts | 95 +++++++++++ .../tsserver/postPasteImportFixes.ts | 12 +- 9 files changed, 145 insertions(+), 240 deletions(-) diff --git a/src/harness/client.ts b/src/harness/client.ts index 90ba9dbf76459..142e3871f9899 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -1020,7 +1020,7 @@ export class SessionClient implements LanguageService { const args: protocol.GetPostPasteImportFixesRequestArgs = { file: targetFile, copies: copies.map(copy => ({ text: copy.text, range: copy.copyRange ? { file: copy.copyRange.file, start: this.positionToOneBasedLineOffset(copy.copyRange.file, copy.copyRange.range.pos), end: this.positionToOneBasedLineOffset(copy.copyRange.file, copy.copyRange.range.end) } : undefined })), - pastes: pastes.map(paste => ({ start: this.positionToOneBasedLineOffset(targetFile, paste.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.end) })), + pastes: pastes.map(paste => ({ start: this.positionToOneBasedLineOffset(targetFile, paste.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.end)})), }; const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); const response = this.processResponse(request); diff --git a/src/server/project.ts b/src/server/project.ts index c3a4ae7616cbf..7838357e8bb78 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2216,17 +2216,15 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo } /** @internal */ - runWithTemporaryFileUpdate(rootFile: string, pastedText: string): { updatedFile: SourceFile | undefined; updatedProgram: Program | undefined; originalProgram: ts.Program | undefined; } { + runWithTemporaryFileUpdate(rootFile: string, pastedText: string, cb: (updatedProgram: Program | undefined, originalProgram: Program | undefined, updatedFile: SourceFile) => void) { const originalProgram = this.program; - Debug.assert(this.program && this.program.getSourceFile(rootFile)); + const originalText = this.program?.getSourceFile(rootFile)?.getText(); + Debug.assert(this.program && this.program.getSourceFile(rootFile) && originalText); + this.getScriptInfo(rootFile)?.editContent(0, this.program.getSourceFile(rootFile)!.getText().length, pastedText); this.updateGraph(); - return { updatedFile: (this.program?.getSourceFile(rootFile)), updatedProgram: this.program, originalProgram }; - } - - /** @internal */ - revertUpdatedFile(rootFile: string, updatedText: string, originalText: string) { - this.getScriptInfo(rootFile)?.editContent(0, updatedText.length, originalText); + cb(this.program, originalProgram, (this.program?.getSourceFile(rootFile))!); + this.getScriptInfo(rootFile)?.editContent(0, this.program.getSourceFile(rootFile)!.getText().length, originalText); this.updateGraph(); } diff --git a/src/server/session.ts b/src/server/session.ts index e0e151958a2d0..33cd757296493 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2799,12 +2799,11 @@ export class Session implements EventSender { private getPostPasteImportFixes(args: protocol.GetPostPasteImportFixesRequestArgs): protocol.PostPasteImportAction | undefined { const { file, project } = this.getFileAndProject(args); - //const pastes = args.pastes.map(paste => ({ text: paste.text, range: this.getRange({ file, startLine: paste.range.start.line, startOffset: paste.range.start.offset, endLine: paste.range.end.line, endOffset: paste.range.end.offset }, project.getScriptInfoForNormalizedPath(file)!) })); - //const pastes = args.pastes.map(paste => this.getRange({ file, startLine: paste.start.line, startOffset: paste.start.offset, endLine: paste.end.line, endOffset: paste.end.offset }, project.getScriptInfoForNormalizedPath(file)!)); const copyFile = args.copies[0].range ? args.copies[0].range.file : undefined; const result = project.getLanguageService().getPostPasteImportFixes( file, - args.copies.map(copy => ({ text: copy.text, copyRange: copy.range && copyFile ? { file: copy.range.file, range: this.getRange({ file: copyFile, startLine: copy.range.start.line, startOffset: copy.range.start.offset, endLine: copy.range.end.line, endOffset: copy.range.end.offset }, project.getScriptInfoForNormalizedPath(toNormalizedPath(copyFile))!) }: undefined })), + args.copies.map(copy => ({ text: copy.text, copyRange: copy.range && copyFile + ? { file: copy.range.file, range: this.getRange({ file: copyFile, startLine: copy.range.start.line, startOffset: copy.range.start.offset, endLine: copy.range.end.line, endOffset: copy.range.end.offset }, project.getScriptInfoForNormalizedPath(toNormalizedPath(copyFile))!) }: undefined })), args.pastes.map(paste => this.getRange({ file, startLine: paste.start.line, startOffset: paste.start.offset, endLine: paste.end.line, endOffset: paste.end.offset }, project.getScriptInfoForNormalizedPath(file)!)), this.getPreferences(file), this.getFormatOptions(file)); diff --git a/src/services/postPasteImportFixes.ts b/src/services/postPasteImportFixes.ts index 0030b727d94de..c2d8ffaf3ba92 100644 --- a/src/services/postPasteImportFixes.ts +++ b/src/services/postPasteImportFixes.ts @@ -1,50 +1,31 @@ import { addRange, - append, } from "../compiler/core"; import { - AnyImportOrRequireStatement, CancellationToken, - Identifier, - ModifierFlags, - Program, SourceFile, Statement, SymbolFlags, TextRange, - TypeChecker, UserPreferences, } from "../compiler/types"; import { getLineOfLocalPosition, - hasSyntacticModifier, - skipAlias, } from "../compiler/utilities"; import { codefix, - Debug, - factory, fileShouldUseJavaScriptRequire, forEachChild, formatting, getQuotePreference, + getTargetFileImportsAndAddExportInOldFile, insertImports, isIdentifier, - nodeSeenTracker, - Symbol, textChanges, } from "./_namespaces/ts"; import { - addExportToChanges, - filterImport, - forEachImportInStatement, getExistingLocals, - getTopLevelDeclarationStatement, getUsageInfo, - isTopLevelDeclaration, - makeImportOrRequire, - moduleSpecifierFromImport, - nameOfTopLevelDeclaration, } from "./refactors/moveToFile"; import { CodeFixContextBase, @@ -56,15 +37,12 @@ import { /** @internal */ export function postPasteImportFixesProvider( targetFile: SourceFile, - //pastes: { text: string; range: TextRange; }[], copies: { text: string; copyRange?: { file: SourceFile; range: TextRange;} }[], pastes: TextRange[], host: LanguageServiceHost, preferences: UserPreferences, formatContext: formatting.FormatContext, cancellationToken: CancellationToken, - //originalFile?: SourceFile, - //copyLocation?: { file: string; range: TextRange; }, ): PostPasteImportFixes { const changes: FileTextChanges[] = textChanges.ChangeTracker.with({ host, formatContext, preferences }, changeTracker => postPasteFixes(targetFile, copies, pastes, host, preferences, formatContext, cancellationToken, changeTracker)); return { edits: changes }; @@ -81,112 +59,46 @@ function postPasteFixes( changes: textChanges.ChangeTracker, ) { const copy = copies[0]; - const updatedTargetFile = host.runWithTemporaryFileUpdate?.(targetFile.fileName, targetFile.getText().slice(0, pastes[0].pos) + copy.text + targetFile.getText().slice(pastes[0].end)); const statements: Statement[] = []; - Debug.assert(updatedTargetFile && updatedTargetFile.updatedFile && updatedTargetFile.originalProgram && updatedTargetFile.updatedProgram); - - if (copy.copyRange) { - const _start = getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.pos); - const _end = getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.end); - addRange(statements, copy.copyRange.file.statements, getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.pos), getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.end) + 1); - const usage = getUsageInfo(copy.copyRange.file, statements, updatedTargetFile.originalProgram.getTypeChecker(), getExistingLocals(updatedTargetFile.updatedFile, statements, updatedTargetFile.originalProgram.getTypeChecker())); - const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); - - const imports = getImportsFromKnownOriginalFile(copy.copyRange.file, targetFile, updatedTargetFile.updatedProgram, importAdder, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, preferences, host, updatedTargetFile.originalProgram.getTypeChecker()); - if (imports.length > 0) { - insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); - } - importAdder.writeFixes(changes, getQuotePreference(copy.copyRange.file, preferences)); - host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); - } - else { - const context: CodeFixContextBase = { - sourceFile: updatedTargetFile.updatedFile, - program: updatedTargetFile.originalProgram, - cancellationToken, - host, - preferences, - formatContext, - }; - const importAdder = codefix.createImportAdder(updatedTargetFile.updatedFile, updatedTargetFile.updatedProgram, preferences, host); - forEachChild(updatedTargetFile.updatedFile, function cb(node) { - if (isIdentifier(node)) { - if (!updatedTargetFile.originalProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ false)) { - // generate imports - importAdder.addImportForUnresolvedIdentifier(context, node, /*useAutoImportProvider*/ true); - } - } - else { - node.forEachChild(cb); - } - }); - importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); - host.revertUpdatedFile?.(targetFile.fileName, updatedTargetFile.updatedFile.text, targetFile.text); - } - pastes.forEach((paste) => { - changes.replaceRangeWithText(targetFile, { pos: paste.pos, end: paste.end }, copy.text); - //range.pos === range.end ? changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text) : changes.replaceRangeWithText(targetFile, { pos: range.pos, end: range.end }, text); - }); -} - -function getImportsFromKnownOriginalFile( - originalFile: SourceFile, - targetFile: SourceFile, - program: Program, - importAdder: codefix.ImportAdder, - importsToCopy: Map, - targetFileImportsFromOldFile: Set, - changes: textChanges.ChangeTracker, - preferences: UserPreferences, - host: LanguageServiceHost, - checker: TypeChecker, -) { - const copiedOldImports: AnyImportOrRequireStatement[] = []; - importsToCopy.forEach((isValidTypeOnlyUseSite, symbol) => { - try { - importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker), isValidTypeOnlyUseSite); - } - catch { - for (const oldStatement of originalFile.statements) { - forEachImportInStatement(oldStatement, i => { - append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); - }); + + host.runWithTemporaryFileUpdate?.(targetFile.fileName, targetFile.getText().slice(0, pastes[0].pos) + copy.text + targetFile.getText().slice(pastes[0].end), (updatedProgram, originalProgram, updatedFile) => { + if (copy.copyRange) { + addRange(statements, copy.copyRange.file.statements, getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.pos), getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.end) + 1); + const usage = getUsageInfo(copy.copyRange.file, statements, originalProgram!.getTypeChecker(), getExistingLocals(updatedFile, statements, originalProgram!.getTypeChecker())); + const importAdder = codefix.createImportAdder(updatedFile, updatedProgram!, preferences, host); + + const imports = getTargetFileImportsAndAddExportInOldFile(copy.copyRange.file, targetFile.fileName, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, + originalProgram!.getTypeChecker(), updatedProgram!, host, !fileShouldUseJavaScriptRequire(targetFile.fileName, updatedProgram!, host, !!copy.copyRange.file.commonJsModuleIndicator), getQuotePreference(targetFile, preferences), importAdder); + if (imports.length > 0) { + insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); } + importAdder.writeFixes(changes, getQuotePreference(copy.copyRange.file, preferences)); } - }); - - const useEsModuleSyntax = !fileShouldUseJavaScriptRequire(targetFile.fileName, program, host, !!originalFile.commonJsModuleIndicator); - const quotePreference = getQuotePreference(targetFile, preferences); - // Also, import things used from the old file, and insert 'export' modifiers as necessary in the old file. - let oldFileDefault: Identifier | undefined; - const oldFileNamedImports: string[] = []; - const markSeenTop = nodeSeenTracker(); // Needed because multiple declarations may appear in `const x = 0, y = 1;`. - targetFileImportsFromOldFile.forEach(symbol => { - if (!symbol.declarations) { - return; - } - for (const decl of symbol.declarations) { - if (!isTopLevelDeclaration(decl)) continue; - const name = nameOfTopLevelDeclaration(decl); - if (!name) continue; - - const top = getTopLevelDeclarationStatement(decl); - if (markSeenTop(top)) { - addExportToChanges(originalFile, top, name, changes, useEsModuleSyntax); - } - if (importAdder && checker.isUnknownSymbol(symbol)) { - importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker)); - } - else { - if (hasSyntacticModifier(decl, ModifierFlags.Default)) { - oldFileDefault = name; + else { + const context: CodeFixContextBase = { + sourceFile: updatedFile, + program: originalProgram!, + cancellationToken, + host, + preferences, + formatContext, + }; + const importAdder = codefix.createImportAdder(updatedFile, updatedProgram!, preferences, host); + forEachChild(updatedFile, function cb(node) { + if (isIdentifier(node)) { + if (!originalProgram?.getTypeChecker().resolveName(node.text, node, SymbolFlags.All, /*excludeGlobals*/ false)) { + // generate imports + importAdder.addImportForUnresolvedIdentifier(context, node, /*useAutoImportProvider*/ true); + } } else { - oldFileNamedImports.push(name.text); + node.forEachChild(cb); } - } + }); + importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); } + }); + pastes.forEach((paste) => { + changes.replaceRangeWithText(targetFile, { pos: paste.pos, end: paste.end }, copy.text); }); - - return append(copiedOldImports, makeImportOrRequire(targetFile, oldFileDefault, oldFileNamedImports, originalFile.fileName, program, host, useEsModuleSyntax, quotePreference)); -} +} \ No newline at end of file diff --git a/src/services/refactors/moveToFile.ts b/src/services/refactors/moveToFile.ts index c95163d4b71fd..22610c5ed63c6 100644 --- a/src/services/refactors/moveToFile.ts +++ b/src/services/refactors/moveToFile.ts @@ -3,7 +3,6 @@ import { } from "../../compiler/moduleSpecifiers"; import { AnyImportOrRequireStatement, - append, ApplicableRefactorInfo, arrayFrom, AssignmentDeclarationKind, @@ -58,6 +57,7 @@ import { getRelativePathFromFile, getSourceFileOfNode, getSynthesizedDeepClone, + getTargetFileImportsAndAddExportInOldFile, getUniqueName, hasJSFileExtension, hasSyntacticModifier, @@ -112,7 +112,6 @@ import { NamedImportBindings, Node, NodeFlags, - nodeSeenTracker, normalizePath, ObjectBindingElementWithoutPropertyName, Program, @@ -272,95 +271,6 @@ function getNewStatementsAndRemoveFromOldFile( ]; } -function getTargetFileImportsAndAddExportInOldFile( - oldFile: SourceFile, - targetFile: string, - importsToCopy: Map, - targetFileImportsFromOldFile: Set, - changes: textChanges.ChangeTracker, - checker: TypeChecker, - program: Program, - host: LanguageServiceHost, - useEsModuleSyntax: boolean, - quotePreference: QuotePreference, - importAdder?: codefix.ImportAdder, -): readonly AnyImportOrRequireStatement[] { - const copiedOldImports: AnyImportOrRequireStatement[] = []; - /** - * Recomputing the imports is preferred with importAdder because it manages multiple import additions for a file and writes then to a ChangeTracker, - * but sometimes it fails because of unresolved imports from files, or when a source file is not available for the target file (in this case when creating a new file). - * So in that case, fall back to copying the import verbatim. - */ - if (importAdder) { - importsToCopy.forEach((isValidTypeOnlyUseSite, symbol) => { - try { - importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker), isValidTypeOnlyUseSite); - } - catch { - for (const oldStatement of oldFile.statements) { - forEachImportInStatement(oldStatement, i => { - append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); - }); - } - } - }); - } - else { - const targetSourceFile = program.getSourceFile(targetFile); // Would be undefined for a new file - for (const oldStatement of oldFile.statements) { - forEachImportInStatement(oldStatement, i => { - // Recomputing module specifier - const moduleSpecifier = moduleSpecifierFromImport(i); - const compilerOptions = program.getCompilerOptions(); - const resolved = program.getResolvedModuleFromModuleSpecifier(moduleSpecifier); - const fileName = resolved?.resolvedModule?.resolvedFileName; - if (fileName && targetSourceFile) { - const newModuleSpecifier = getModuleSpecifier(compilerOptions, targetSourceFile, targetSourceFile.fileName, fileName, createModuleSpecifierResolutionHost(program, host)); - append(copiedOldImports, filterImport(i, makeStringLiteral(newModuleSpecifier, quotePreference), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); - } - else { - append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); - } - }); - } - } - - // Also, import things used from the old file, and insert 'export' modifiers as necessary in the old file. - const targetFileSourceFile = program.getSourceFile(targetFile); - let oldFileDefault: Identifier | undefined; - const oldFileNamedImports: string[] = []; - const markSeenTop = nodeSeenTracker(); // Needed because multiple declarations may appear in `const x = 0, y = 1;`. - targetFileImportsFromOldFile.forEach(symbol => { - if (!symbol.declarations) { - return; - } - for (const decl of symbol.declarations) { - if (!isTopLevelDeclaration(decl)) continue; - const name = nameOfTopLevelDeclaration(decl); - if (!name) continue; - - const top = getTopLevelDeclarationStatement(decl); - if (markSeenTop(top)) { - addExportToChanges(oldFile, top, name, changes, useEsModuleSyntax); - } - if (importAdder && checker.isUnknownSymbol(symbol)) { - importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker)); - } - else { - if (hasSyntacticModifier(decl, ModifierFlags.Default)) { - oldFileDefault = name; - } - else { - oldFileNamedImports.push(name.text); - } - } - } - }); - return targetFileSourceFile - ? append(copiedOldImports, makeImportOrRequire(targetFileSourceFile, oldFileDefault, oldFileNamedImports, oldFile.fileName, program, host, useEsModuleSyntax, quotePreference)) - : append(copiedOldImports, makeImportOrRequire(oldFile, oldFileDefault, oldFileNamedImports, oldFile.fileName, program, host, useEsModuleSyntax, quotePreference)); -} - /** @internal */ export function addNewFileToTsconfig(program: Program, changes: textChanges.ChangeTracker, oldFileName: string, newFileNameWithExtension: string, getCanonicalFileName: GetCanonicalFileName): void { const cfg = program.getCompilerOptions().configFile; diff --git a/src/services/services.ts b/src/services/services.ts index 526caf59ebd85..4e586c61b055e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2093,8 +2093,6 @@ export function createLanguageService( function getPostPasteImportFixes( targetFile: string, - // pastes: { text: string; range: TextRange; }[], - // copySpan: { file: string; range: TextRange; } | undefined, copies: { text: string; copyRange?: { file: string; range: TextRange;} }[], pastes: TextRange[], preferences: UserPreferences, diff --git a/src/services/types.ts b/src/services/types.ts index 21af24777c4ad..e89d7025322e4 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -431,8 +431,7 @@ export interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalR getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined; /** @internal */ onReleaseParsedCommandLine?(configFileName: string, oldResolvedRef: ResolvedProjectReference | undefined, optionOptions: CompilerOptions): void; /** @internal */ getIncompleteCompletionsCache?(): IncompleteCompletionsCache; - /** @internal */ runWithTemporaryFileUpdate?(rootFile: string, pastedText: string): { updatedFile: SourceFile | undefined; updatedProgram: Program | undefined; originalProgram: Program | undefined; }; - /** @internal */ revertUpdatedFile?(rootFile: string, updatedText: string, originalText: string): void; + /** @internal */ runWithTemporaryFileUpdate?(rootFile: string, pastedText: string, cb: (updatedProgram: Program | undefined, originalProgram: Program | undefined, updatedPastedText: SourceFile) => void): void; jsDocParsingMode?: JSDocParsingMode | undefined; } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 0b2072f449008..508919da251a1 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1,9 +1,12 @@ +import { getModuleSpecifier } from "../compiler/_namespaces/ts.moduleSpecifiers"; import { __String, addEmitFlags, addSyntheticLeadingComment, addSyntheticTrailingComment, AnyImportOrRequireStatement, + append, + //append, assertType, AssignmentDeclarationKind, BinaryExpression, @@ -377,6 +380,8 @@ import { walkUpParenthesizedExpressions, YieldExpression, } from "./_namespaces/ts"; +import { addExportToChanges, filterImport, forEachImportInStatement, getTopLevelDeclarationStatement, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./_namespaces/ts.refactor"; +//import { addExportToChanges, filterImport, forEachImportInStatement, getTopLevelDeclarationStatement, isTopLevelDeclaration, makeImportOrRequire,moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./refactors/moveToFile"; // These utilities are common to multiple language service features. // #region @@ -4274,3 +4279,93 @@ export function fileShouldUseJavaScriptRequire(file: SourceFile | string, progra } return preferRequire; } + +/** @internal */ +export function getTargetFileImportsAndAddExportInOldFile( + oldFile: SourceFile, + targetFile: string, + importsToCopy: Map, + targetFileImportsFromOldFile: Set, + changes: textChanges.ChangeTracker, + checker: TypeChecker, + program: Program, + host: LanguageServiceHost, + useEsModuleSyntax: boolean, + quotePreference: QuotePreference, + importAdder?: codefix.ImportAdder, +): readonly AnyImportOrRequireStatement[] { + const copiedOldImports: AnyImportOrRequireStatement[] = []; + /** + * Recomputing the imports is preferred with importAdder because it manages multiple import additions for a file and writes then to a ChangeTracker, + * but sometimes it fails because of unresolved imports from files, or when a source file is not available for the target file (in this case when creating a new file). + * So in that case, fall back to copying the import verbatim. + */ + if (importAdder) { + importsToCopy.forEach((isValidTypeOnlyUseSite, symbol) => { + try { + importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker), isValidTypeOnlyUseSite); + } + catch { + for (const oldStatement of oldFile.statements) { + forEachImportInStatement(oldStatement, i => { + append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + }); + } + } + }); + } + else { + const targetSourceFile = program.getSourceFile(targetFile); // Would be undefined for a new file + for (const oldStatement of oldFile.statements) { + forEachImportInStatement(oldStatement, i => { + // Recomputing module specifier + const moduleSpecifier = moduleSpecifierFromImport(i); + const compilerOptions = program.getCompilerOptions(); + const resolved = program.getResolvedModuleFromModuleSpecifier(moduleSpecifier); + const fileName = resolved?.resolvedModule?.resolvedFileName; + if (fileName && targetSourceFile) { + const newModuleSpecifier = getModuleSpecifier(compilerOptions, targetSourceFile, targetSourceFile.fileName, fileName, createModuleSpecifierResolutionHost(program, host)); + append(copiedOldImports, filterImport(i, makeStringLiteral(newModuleSpecifier, quotePreference), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + } + else { + append(copiedOldImports, filterImport(i, factory.createStringLiteral(moduleSpecifierFromImport(i).text), name => importsToCopy.has(checker.getSymbolAtLocation(name)!))); + } + }); + } + } + + // Also, import things used from the old file, and insert 'export' modifiers as necessary in the old file. + const targetFileSourceFile = program.getSourceFile(targetFile); + let oldFileDefault: Identifier | undefined; + const oldFileNamedImports: string[] = []; + const markSeenTop = nodeSeenTracker(); // Needed because multiple declarations may appear in `const x = 0, y = 1;`. + targetFileImportsFromOldFile.forEach(symbol => { + if (!symbol.declarations) { + return; + } + for (const decl of symbol.declarations) { + if (!isTopLevelDeclaration(decl)) continue; + const name = nameOfTopLevelDeclaration(decl); + if (!name) continue; + + const top = getTopLevelDeclarationStatement(decl); + if (markSeenTop(top)) { + addExportToChanges(oldFile, top, name, changes, useEsModuleSyntax); + } + if (importAdder && checker.isUnknownSymbol(symbol)) { + importAdder.addImportFromExportedSymbol(skipAlias(symbol, checker)); + } + else { + if (hasSyntacticModifier(decl, ModifierFlags.Default)) { + oldFileDefault = name; + } + else { + oldFileNamedImports.push(name.text); + } + } + } + }); + return targetFileSourceFile + ? append(copiedOldImports, makeImportOrRequire(targetFileSourceFile, oldFileDefault, oldFileNamedImports, oldFile.fileName, program, host, useEsModuleSyntax, quotePreference)) + : append(copiedOldImports, makeImportOrRequire(oldFile, oldFileDefault, oldFileNamedImports, oldFile.fileName, program, host, useEsModuleSyntax, quotePreference)); +} \ No newline at end of file diff --git a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts index 765792936db5b..0d6c504638637 100644 --- a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts +++ b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts @@ -31,16 +31,10 @@ const c = 3;`; const session = new TestSession(host); openFilesForSession([target], session); - const originalContent = target.content; - const originalProgram = session.getProjectService().configuredProjects.get(tsconfig.path)!.getLanguageService().getProgram(); - const hostProject = session.getProjectService().configuredProjects.get(tsconfig.path)!; - const updatedContent = hostProject.runWithTemporaryFileUpdate(target.path, pastedText); - - if (updatedContent.updatedFile !== undefined) { - hostProject.revertUpdatedFile(target.path, updatedContent.updatedFile.getText(), originalContent); - } - assert.strictEqual(hostProject.getCurrentProgram()?.getSourceFileByPath(target.path as ts.Path)?.getText(), originalProgram?.getSourceFileByPath(target.path as ts.Path)?.getText()); + hostProject.runWithTemporaryFileUpdate(target.path, pastedText, (_updatedProgram, _originalProgram, _updatedFile)=>{}); + + assert.strictEqual(hostProject.getCurrentProgram()?.getSourceFileByPath(target.path as ts.Path)?.getText(), target.content); baselineTsserverLogs("getPostPasteImportFixes", "Returns the same file unchanged ", session); }); }); From c6b6f2323ef3cdc864158ee31b72c764c8000f45 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Tue, 20 Feb 2024 13:10:25 -0800 Subject: [PATCH 15/18] fixing formatting --- src/harness/client.ts | 6 +++--- src/harness/fourslashInterfaceImpl.ts | 4 ++-- src/server/project.ts | 2 +- src/server/protocol.ts | 6 +++--- src/server/session.ts | 12 ++++++++---- src/services/postPasteImportFixes.ts | 17 ++++++++--------- src/services/services.ts | 10 ++++++---- src/services/types.ts | 2 +- src/services/utilities.ts | 17 ++++++++++++++--- .../unittests/tsserver/postPasteImportFixes.ts | 4 ++-- 10 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/harness/client.ts b/src/harness/client.ts index 142e3871f9899..a4da1f99ea034 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -1012,15 +1012,15 @@ export class SessionClient implements LanguageService { getPostPasteImportFixes( targetFile: string, - copies: { text: string; copyRange?: { file: string; range: TextRange;} }[], + copies: { text: string; copyRange?: { file: string; range: TextRange; }; }[], pastes: TextRange[], _preferences: UserPreferences, - _formatOptions: FormatCodeSettings + _formatOptions: FormatCodeSettings, ): PostPasteImportFixes { const args: protocol.GetPostPasteImportFixesRequestArgs = { file: targetFile, copies: copies.map(copy => ({ text: copy.text, range: copy.copyRange ? { file: copy.copyRange.file, start: this.positionToOneBasedLineOffset(copy.copyRange.file, copy.copyRange.range.pos), end: this.positionToOneBasedLineOffset(copy.copyRange.file, copy.copyRange.range.end) } : undefined })), - pastes: pastes.map(paste => ({ start: this.positionToOneBasedLineOffset(targetFile, paste.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.end)})), + pastes: pastes.map(paste => ({ start: this.positionToOneBasedLineOffset(targetFile, paste.pos), end: this.positionToOneBasedLineOffset(targetFile, paste.end) })), }; const request = this.processRequest(protocol.CommandTypes.GetPostPasteImportFixes, args); const response = this.processResponse(request); diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 4926fb1c49bd8..93c8b999871a6 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1936,8 +1936,8 @@ export interface MoveToFileOptions { export interface PostPasteImportFixOptions { readonly newFileContents: { readonly [fileName: string]: string; }; - readonly copies: { text: string; copyRange?: { file: string; range: ts.TextRange;} }[], - readonly pastes: ts.TextRange[], + readonly copies: { text: string; copyRange?: { file: string; range: ts.TextRange; }; }[]; + readonly pastes: ts.TextRange[]; readonly preferences: ts.UserPreferences; } diff --git a/src/server/project.ts b/src/server/project.ts index 7838357e8bb78..540dc65140de0 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2220,7 +2220,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo const originalProgram = this.program; const originalText = this.program?.getSourceFile(rootFile)?.getText(); Debug.assert(this.program && this.program.getSourceFile(rootFile) && originalText); - + this.getScriptInfo(rootFile)?.editContent(0, this.program.getSourceFile(rootFile)!.getText().length, pastedText); this.updateGraph(); cb(this.program, originalProgram, (this.program?.getSourceFile(rootFile))!); diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 76967b4fc6ac1..de9a4d1e75d7f 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -642,11 +642,11 @@ export interface GetPostPasteImportFixesRequest extends Request { export type GetPostPasteImportFixesRequestArgs = FileRequestArgs & { copies: { - text: string; - range?: FileSpan; + text: string; + range?: FileSpan; }[]; pastes: TextSpan[]; - }; +}; export interface GetPostPasteImportFixesResponse extends Response { body: PostPasteImportAction; } diff --git a/src/server/session.ts b/src/server/session.ts index 33cd757296493..1aa461bb2db54 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2802,11 +2802,15 @@ export class Session implements EventSender { const copyFile = args.copies[0].range ? args.copies[0].range.file : undefined; const result = project.getLanguageService().getPostPasteImportFixes( file, - args.copies.map(copy => ({ text: copy.text, copyRange: copy.range && copyFile - ? { file: copy.range.file, range: this.getRange({ file: copyFile, startLine: copy.range.start.line, startOffset: copy.range.start.offset, endLine: copy.range.end.line, endOffset: copy.range.end.offset }, project.getScriptInfoForNormalizedPath(toNormalizedPath(copyFile))!) }: undefined })), - args.pastes.map(paste => this.getRange({ file, startLine: paste.start.line, startOffset: paste.start.offset, endLine: paste.end.line, endOffset: paste.end.offset }, project.getScriptInfoForNormalizedPath(file)!)), + args.copies.map(copy => ({ + text: copy.text, + copyRange: copy.range && copyFile + ? { file: copy.range.file, range: this.getRange({ file: copyFile, startLine: copy.range.start.line, startOffset: copy.range.start.offset, endLine: copy.range.end.line, endOffset: copy.range.end.offset }, project.getScriptInfoForNormalizedPath(toNormalizedPath(copyFile))!) } : undefined, + })), + args.pastes.map(paste => this.getRange({ file, startLine: paste.start.line, startOffset: paste.start.offset, endLine: paste.end.line, endOffset: paste.end.offset }, project.getScriptInfoForNormalizedPath(file)!)), this.getPreferences(file), - this.getFormatOptions(file)); + this.getFormatOptions(file), + ); if (result === undefined) { return undefined; } diff --git a/src/services/postPasteImportFixes.ts b/src/services/postPasteImportFixes.ts index c2d8ffaf3ba92..029aa78aed44a 100644 --- a/src/services/postPasteImportFixes.ts +++ b/src/services/postPasteImportFixes.ts @@ -37,7 +37,7 @@ import { /** @internal */ export function postPasteImportFixesProvider( targetFile: SourceFile, - copies: { text: string; copyRange?: { file: SourceFile; range: TextRange;} }[], + copies: { text: string; copyRange?: { file: SourceFile; range: TextRange; }; }[], pastes: TextRange[], host: LanguageServiceHost, preferences: UserPreferences, @@ -50,7 +50,7 @@ export function postPasteImportFixesProvider( function postPasteFixes( targetFile: SourceFile, - copies: { text: string; copyRange?: { file: SourceFile; range: TextRange;} }[], + copies: { text: string; copyRange?: { file: SourceFile; range: TextRange; }; }[], pastes: TextRange[], host: LanguageServiceHost, preferences: UserPreferences, @@ -60,15 +60,14 @@ function postPasteFixes( ) { const copy = copies[0]; const statements: Statement[] = []; - + host.runWithTemporaryFileUpdate?.(targetFile.fileName, targetFile.getText().slice(0, pastes[0].pos) + copy.text + targetFile.getText().slice(pastes[0].end), (updatedProgram, originalProgram, updatedFile) => { if (copy.copyRange) { addRange(statements, copy.copyRange.file.statements, getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.pos), getLineOfLocalPosition(copy.copyRange.file, copy.copyRange.range.end) + 1); const usage = getUsageInfo(copy.copyRange.file, statements, originalProgram!.getTypeChecker(), getExistingLocals(updatedFile, statements, originalProgram!.getTypeChecker())); const importAdder = codefix.createImportAdder(updatedFile, updatedProgram!, preferences, host); - - const imports = getTargetFileImportsAndAddExportInOldFile(copy.copyRange.file, targetFile.fileName, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, - originalProgram!.getTypeChecker(), updatedProgram!, host, !fileShouldUseJavaScriptRequire(targetFile.fileName, updatedProgram!, host, !!copy.copyRange.file.commonJsModuleIndicator), getQuotePreference(targetFile, preferences), importAdder); + + const imports = getTargetFileImportsAndAddExportInOldFile(copy.copyRange.file, targetFile.fileName, usage.oldImportsNeededByTargetFile, usage.targetFileImportsFromOldFile, changes, originalProgram!.getTypeChecker(), updatedProgram!, host, !fileShouldUseJavaScriptRequire(targetFile.fileName, updatedProgram!, host, !!copy.copyRange.file.commonJsModuleIndicator), getQuotePreference(targetFile, preferences), importAdder); if (imports.length > 0) { insertImports(changes, targetFile, imports, /*blankLineBetween*/ true, preferences); } @@ -97,8 +96,8 @@ function postPasteFixes( }); importAdder.writeFixes(changes, getQuotePreference(targetFile, preferences)); } - }); - pastes.forEach((paste) => { + }); + pastes.forEach(paste => { changes.replaceRangeWithText(targetFile, { pos: paste.pos, end: paste.end }, copy.text); }); -} \ No newline at end of file +} diff --git a/src/services/services.ts b/src/services/services.ts index 59904c6820f67..166e2b7c85243 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2095,7 +2095,7 @@ export function createLanguageService( function getPostPasteImportFixes( targetFile: string, - copies: { text: string; copyRange?: { file: string; range: TextRange;} }[], + copies: { text: string; copyRange?: { file: string; range: TextRange; }; }[], pastes: TextRange[], preferences: UserPreferences, formatOptions: FormatCodeSettings, @@ -2105,9 +2105,11 @@ export function createLanguageService( getValidSourceFile(targetFile), copies.map(({ text, copyRange }) => ({ text, copyRange: copyRange ? { file: getValidSourceFile(copyRange.file), range: copyRange.range } : undefined })), pastes, - host, - preferences, - formatting.getFormatContext(formatOptions, host), cancellationToken); + host, + preferences, + formatting.getFormatContext(formatOptions, host), + cancellationToken, + ); } function getNodeForQuickInfo(node: Node): Node { diff --git a/src/services/types.ts b/src/services/types.ts index e89d7025322e4..33ed3ede6baca 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -686,7 +686,7 @@ export interface LanguageService { dispose(): void; getPostPasteImportFixes( targetFile: string, - copies: { text: string; range?: { file: string; range: TextRange;} }[], + copies: { text: string; range?: { file: string; range: TextRange; }; }[], pastes: TextRange[], preferences: UserPreferences, formatOptions: FormatCodeSettings, diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 67499e0382a1b..e476ceb506cf0 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1,4 +1,6 @@ -import { getModuleSpecifier } from "../compiler/_namespaces/ts.moduleSpecifiers"; +import { + getModuleSpecifier, +} from "../compiler/_namespaces/ts.moduleSpecifiers"; import { __String, addEmitFlags, @@ -380,7 +382,16 @@ import { walkUpParenthesizedExpressions, YieldExpression, } from "./_namespaces/ts"; -import { addExportToChanges, filterImport, forEachImportInStatement, getTopLevelDeclarationStatement, isTopLevelDeclaration, makeImportOrRequire, moduleSpecifierFromImport, nameOfTopLevelDeclaration } from "./_namespaces/ts.refactor"; +import { + addExportToChanges, + filterImport, + forEachImportInStatement, + getTopLevelDeclarationStatement, + isTopLevelDeclaration, + makeImportOrRequire, + moduleSpecifierFromImport, + nameOfTopLevelDeclaration, +} from "./_namespaces/ts.refactor"; // These utilities are common to multiple language service features. // #region @@ -4380,4 +4391,4 @@ export function getTargetFileImportsAndAddExportInOldFile( return targetFileSourceFile ? append(copiedOldImports, makeImportOrRequire(targetFileSourceFile, oldFileDefault, oldFileNamedImports, oldFile.fileName, program, host, useEsModuleSyntax, quotePreference)) : append(copiedOldImports, makeImportOrRequire(oldFile, oldFileDefault, oldFileNamedImports, oldFile.fileName, program, host, useEsModuleSyntax, quotePreference)); -} \ No newline at end of file +} diff --git a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts index 0d6c504638637..90c0c4c3bc954 100644 --- a/src/testRunner/unittests/tsserver/postPasteImportFixes.ts +++ b/src/testRunner/unittests/tsserver/postPasteImportFixes.ts @@ -32,8 +32,8 @@ const c = 3;`; openFilesForSession([target], session); const hostProject = session.getProjectService().configuredProjects.get(tsconfig.path)!; - hostProject.runWithTemporaryFileUpdate(target.path, pastedText, (_updatedProgram, _originalProgram, _updatedFile)=>{}); - + hostProject.runWithTemporaryFileUpdate(target.path, pastedText, (_updatedProgram, _originalProgram, _updatedFile) => {}); + assert.strictEqual(hostProject.getCurrentProgram()?.getSourceFileByPath(target.path as ts.Path)?.getText(), target.content); baselineTsserverLogs("getPostPasteImportFixes", "Returns the same file unchanged ", session); }); From c8c3e295549bbbcf2b4aace8189a45afb082c89e Mon Sep 17 00:00:00 2001 From: navya9singh Date: Tue, 20 Feb 2024 13:42:29 -0800 Subject: [PATCH 16/18] baseline changes --- .../postPasteImportFixes_existingImports1.js | 22 +++++---- .../postPasteImportFixes_existingImports2.js | 26 +++++----- .../postPasteImportFixes_knownSourceFile.js | 30 ++++++------ .../postPasteImportFixes_multiplePastes1.js | 39 +++++++-------- .../postPasteImportFixes_multiplePastes2.js | 49 +++++++++---------- .../postPasteImportFixes_pasteComments.js | 22 +++++---- .../postPasteImportFixes_unknownSourceFile.js | 22 +++++---- 7 files changed, 109 insertions(+), 101 deletions(-) diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js index b1045e92c98af..c3fd7c5c37059 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports1.js @@ -226,18 +226,20 @@ Info seq [hh:mm:ss:mss] request: "type": "request", "arguments": { "file": "/target.ts", + "copies": [ + { + "text": "const m = t3 + t2 + 1;" + } + ], "pastes": [ { - "text": "const m = t3 + t2 + 1;", - "range": { - "start": { - "line": 4, - "offset": 1 - }, - "end": { - "line": 4, - "offset": 14 - } + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 14 } } ] diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js index a821cde26a378..83a2be3d8686b 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_existingImports2.js @@ -245,32 +245,34 @@ Info seq [hh:mm:ss:mss] request: "type": "request", "arguments": { "file": "/target.ts", - "pastes": [ + "copies": [ { "text": "const m = t3 + t2 + n;", "range": { + "file": "originalFile.ts", "start": { "line": 4, "offset": 1 }, "end": { "line": 4, - "offset": 14 + "offset": 30 } } } ], - "copySpan": { - "file": "originalFile.ts", - "start": { - "line": 3, - "offset": 0 - }, - "end": { - "line": 3, - "offset": 30 + "pastes": [ + { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 14 + } } - } + ] }, "command": "getPostPasteImportFixes" } diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js index 5bc51ef0860f4..ab094df47d509 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_knownSourceFile.js @@ -212,32 +212,34 @@ Info seq [hh:mm:ss:mss] request: "type": "request", "arguments": { "file": "/target.ts", - "pastes": [ + "copies": [ { "text": "const c = a + b;\nconst t = 9;", "range": { + "file": "file2.ts", "start": { - "line": 2, + "line": 3, "offset": 1 }, "end": { - "line": 2, - "offset": 14 + "line": 4, + "offset": 13 } } } ], - "copySpan": { - "file": "file2.ts", - "start": { - "line": 2, - "offset": 0 - }, - "end": { - "line": 3, - "offset": 0 + "pastes": [ + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 14 + } } - } + ] }, "command": "getPostPasteImportFixes" } diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js index ab8f2527e700b..441bd1d77d1be 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes1.js @@ -213,31 +213,30 @@ Info seq [hh:mm:ss:mss] request: "type": "request", "arguments": { "file": "/target.ts", + "copies": [ + { + "text": "const g = p + q;\nfunction e();\nconst f = r + s;" + } + ], "pastes": [ { - "text": "const g = p + q;\nfunction e();\nconst f = r + s;", - "range": { - "start": { - "line": 2, - "offset": 1 - }, - "end": { - "line": 2, - "offset": 1 - } + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 1 } }, { - "text": "const g = p + q;\nfunction e();\nconst f = r + s;", - "range": { - "start": { - "line": 5, - "offset": 1 - }, - "end": { - "line": 5, - "offset": 1 - } + "start": { + "line": 5, + "offset": 1 + }, + "end": { + "line": 5, + "offset": 1 } } ] diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js index 56cfa5f0d74a3..45ed3072ffe8e 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_multiplePastes2.js @@ -216,45 +216,44 @@ Info seq [hh:mm:ss:mss] request: "type": "request", "arguments": { "file": "/target.ts", - "pastes": [ - { - "text": "export const t = aa + bb + r + s;\nconst u = 1;", - "range": { - "start": { - "line": 2, - "offset": 1 - }, - "end": { - "line": 2, - "offset": 13 - } - } - }, + "copies": [ { "text": "export const t = aa + bb + r + s;\nconst u = 1;", "range": { + "file": "file1.ts", "start": { "line": 4, "offset": 1 }, "end": { - "line": 4, - "offset": 1 + "line": 5, + "offset": 13 } } } ], - "copySpan": { - "file": "file1.ts", - "start": { - "line": 3, - "offset": 0 + "pastes": [ + { + "start": { + "line": 2, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 13 + } }, - "end": { - "line": 4, - "offset": 12 + { + "start": { + "line": 4, + "offset": 1 + }, + "end": { + "line": 4, + "offset": 1 + } } - } + ] }, "command": "getPostPasteImportFixes" } diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js index 6bca87a4addb3..e4edb335e213e 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_pasteComments.js @@ -180,18 +180,20 @@ Info seq [hh:mm:ss:mss] request: "type": "request", "arguments": { "file": "/target.ts", + "copies": [ + { + "text": "/**\n* Testing comment line 1\n* line 2\n* line 3\n* line 4\n*/" + } + ], "pastes": [ { - "text": "/**\n* Testing comment line 1\n* line 2\n* line 3\n* line 4\n*/", - "range": { - "start": { - "line": 2, - "offset": 14 - }, - "end": { - "line": 2, - "offset": 14 - } + "start": { + "line": 2, + "offset": 14 + }, + "end": { + "line": 2, + "offset": 14 } } ] diff --git a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js index 596ea7611195c..2a8374ac6ce0a 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js +++ b/tests/baselines/reference/tsserver/fourslashServer/postPasteImportFixes_unknownSourceFile.js @@ -197,18 +197,20 @@ Info seq [hh:mm:ss:mss] request: "type": "request", "arguments": { "file": "/file2.ts", + "copies": [ + { + "text": "interface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }" + } + ], "pastes": [ { - "text": "interface Testing {\n test1: Test1;\n test2: Test2;\n test3: Test3;\n test4: Test4;\n }", - "range": { - "start": { - "line": 3, - "offset": 1 - }, - "end": { - "line": 3, - "offset": 1 - } + "start": { + "line": 3, + "offset": 1 + }, + "end": { + "line": 3, + "offset": 1 } } ] From 5192ff29cff758f360f8ed264b5b1914b603802d Mon Sep 17 00:00:00 2001 From: navya9singh Date: Tue, 20 Feb 2024 15:19:47 -0800 Subject: [PATCH 17/18] accepting baselines --- tests/baselines/reference/api/typescript.d.ts | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 7bbb6029440df..dbcb4cf3d7f28 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -554,11 +554,11 @@ declare namespace ts { arguments: GetPostPasteImportFixesRequestArgs; } type GetPostPasteImportFixesRequestArgs = FileRequestArgs & { - pastes: { + copies: { text: string; - range: TextSpan; + range?: FileSpan; }[]; - copySpan?: FileSpan; + pastes: TextSpan[]; }; interface GetPostPasteImportFixesResponse extends Response { body: PostPasteImportAction; @@ -10686,23 +10686,16 @@ declare namespace ts { dispose(): void; getPostPasteImportFixes( targetFile: string, - pastes: { + copies: { text: string; - range: TextRange; + range?: { + file: string; + range: TextRange; + }; }[], + pastes: TextRange[], preferences: UserPreferences, formatOptions: FormatCodeSettings, - copySpan?: { - file: string; - start: { - line: number; - offset: number; - }; - end: { - line: number; - offset: number; - }; - }, ): PostPasteImportFixes; } interface JsxClosingTagInfo { From fae9b27954322c7e415217916cd0ac9e249c2e60 Mon Sep 17 00:00:00 2001 From: navya9singh Date: Fri, 1 Mar 2024 15:46:31 -0800 Subject: [PATCH 18/18] getting a range of text for extract type, extract symbol, move to file and move to new file refactors --- src/harness/client.ts | 6 +- src/server/protocol.ts | 5 + src/server/session.ts | 3 +- src/services/refactors/extractSymbol.ts | 14 +- src/services/refactors/extractType.ts | 30 +- src/services/refactors/moveToFile.ts | 3 +- src/services/refactors/moveToNewFile.ts | 4 +- src/services/types.ts | 5 + .../tsserver/getApplicableRefactors.ts | 65 ++++ tests/baselines/reference/api/typescript.d.ts | 8 + .../fixExtractToInnerFunctionDuplicaton.js | 288 ++++++++++++++++-- .../moveToFile_emptyTargetFile.js | 48 ++- ...-file'-and-'move-to-new-file'-refactors.js | 155 ++++++++++ ...nge-of-text-for-extract-symbol-refactor.js | 142 +++++++++ ...range-of-text-for-extract-type-refactor.js | 101 ++++++ 15 files changed, 826 insertions(+), 51 deletions(-) create mode 100644 tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-'move-to-file'-and-'move-to-new-file'-refactors.js create mode 100644 tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-extract-symbol-refactor.js create mode 100644 tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-extract-type-refactor.js diff --git a/src/harness/client.ts b/src/harness/client.ts index a4da1f99ea034..20cf9cfded645 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -835,7 +835,11 @@ export class SessionClient implements LanguageService { if (preferences) { // Restore preferences this.configure(oldPreferences || {}); } - return response.body!; // TODO: GH#18217 + // TODO: GH#18217 + return response.body!.map(result => ({ + ...result, + actions: result.actions.map(entry => ({ ...entry, range: entry.range ? createTextSpanFromBounds(this.lineOffsetToPosition(fileName, entry.range.start), this.lineOffsetToPosition(fileName, entry.range.end)) : undefined })), + })); } getMoveToRefactoringFileSuggestions(fileName: string, positionOrRange: number | TextRange): { newFileName: string; files: string[]; } { diff --git a/src/server/protocol.ts b/src/server/protocol.ts index de9a4d1e75d7f..0f8ca06d7720a 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -712,6 +712,11 @@ export interface RefactorActionInfo { * when calling 'GetEditsForRefactor'. */ isInteractive?: boolean; + + /** + * Range of code the refactoring will be applied to. + */ + range?: TextSpan; } export interface GetEditsForRefactorRequest extends Request { diff --git a/src/server/session.ts b/src/server/session.ts index 1aa461bb2db54..61efcb17d1171 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -2752,7 +2752,8 @@ export class Session implements EventSender { private getApplicableRefactors(args: protocol.GetApplicableRefactorsRequestArgs): protocol.ApplicableRefactorInfo[] { const { file, project } = this.getFileAndProject(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file)!; - return project.getLanguageService().getApplicableRefactors(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file), args.triggerReason, args.kind, args.includeInteractiveActions); + const result = project.getLanguageService().getApplicableRefactors(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file), args.triggerReason, args.kind, args.includeInteractiveActions); + return result.map(result => ({ ...result, actions: result.actions.map(action => ({ ...action, range: action.range ? toProtocolTextSpan(action.range, scriptInfo) : undefined })) })); } private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): RefactorEditInfo | protocol.RefactorEditInfo { diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index b9406e8f1b594..0634eed2a3660 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -219,7 +219,7 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea return errors; } - const extractions = getPossibleExtractions(targetRange, context); + const { affectedTextRange, extractions } = getPossibleExtractions(targetRange, context); if (extractions === undefined) { // No extractions possible return emptyArray; @@ -247,6 +247,7 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea description, name: `function_scope_${i}`, kind: extractFunctionAction.kind, + range: { start: affectedTextRange.pos, length: affectedTextRange.end - affectedTextRange.pos }, }); } } @@ -272,6 +273,7 @@ export function getRefactorActionsToExtractSymbol(context: RefactorContext): rea description, name: `constant_scope_${i}`, kind: extractConstantAction.kind, + range: { start: affectedTextRange.pos, length: affectedTextRange.end - affectedTextRange.pos }, }); } } @@ -909,8 +911,8 @@ interface ScopeExtractions { * Each returned ExtractResultForScope corresponds to a possible target scope and is either a set of changes * or an error explaining why we can't extract into that scope. */ -function getPossibleExtractions(targetRange: TargetRange, context: RefactorContext): readonly ScopeExtractions[] | undefined { - const { scopes, readsAndWrites: { functionErrorsPerScope, constantErrorsPerScope } } = getPossibleExtractionsWorker(targetRange, context); +function getPossibleExtractions(targetRange: TargetRange, context: RefactorContext): { readonly affectedTextRange: TextRange; readonly extractions: ScopeExtractions[] | undefined; } { + const { scopes, affectedTextRange, readsAndWrites: { functionErrorsPerScope, constantErrorsPerScope } } = getPossibleExtractionsWorker(targetRange, context); // Need the inner type annotation to avoid https://github.com/Microsoft/TypeScript/issues/7547 const extractions = scopes.map((scope, i): ScopeExtractions => { const functionDescriptionPart = getDescriptionForFunctionInScope(scope); @@ -953,10 +955,10 @@ function getPossibleExtractions(targetRange: TargetRange, context: RefactorConte }, }; }); - return extractions; + return { affectedTextRange, extractions }; } -function getPossibleExtractionsWorker(targetRange: TargetRange, context: RefactorContext): { readonly scopes: Scope[]; readonly readsAndWrites: ReadsAndWrites; } { +function getPossibleExtractionsWorker(targetRange: TargetRange, context: RefactorContext): { readonly scopes: Scope[]; readonly affectedTextRange: TextRange; readonly readsAndWrites: ReadsAndWrites; } { const { file: sourceFile } = context; const scopes = collectEnclosingScopes(targetRange); @@ -969,7 +971,7 @@ function getPossibleExtractionsWorker(targetRange: TargetRange, context: Refacto context.program.getTypeChecker(), context.cancellationToken!, ); - return { scopes, readsAndWrites }; + return { scopes, affectedTextRange: enclosingTextRange, readsAndWrites }; } function getDescriptionForFunctionInScope(scope: Scope): string { diff --git a/src/services/refactors/extractType.ts b/src/services/refactors/extractType.ts index e9d43a1a3c219..3dfcef71511a7 100644 --- a/src/services/refactors/extractType.ts +++ b/src/services/refactors/extractType.ts @@ -99,16 +99,20 @@ registerRefactor(refactorName, { extractToTypeDefAction.kind, ], getAvailableActions: function getRefactorActionsToExtractType(context): readonly ApplicableRefactorInfo[] { - const info = getRangeToExtract(context, context.triggerReason === "invoked"); + const { info, affectedTextRange } = getRangeToExtract(context, context.triggerReason === "invoked"); if (!info) return emptyArray; if (!isRefactorErrorInfo(info)) { - return [{ + const refactorInfo: ApplicableRefactorInfo[] = [{ name: refactorName, description: getLocaleSpecificMessage(Diagnostics.Extract_type), actions: info.isJS ? [extractToTypeDefAction] : append([extractToTypeAliasAction], info.typeElements && extractToInterfaceAction), }]; + return refactorInfo.map(info => ({ + ...info, + actions: info.actions.map(action => ({ ...action, range: affectedTextRange ? { start: affectedTextRange.pos, length: affectedTextRange.end - affectedTextRange.pos } : undefined })), + })); } if (context.preferences.provideRefactorNotApplicableReason) { @@ -127,7 +131,7 @@ registerRefactor(refactorName, { }, getEditsForAction: function getRefactorEditsToExtractType(context, actionName): RefactorEditInfo { const { file } = context; - const info = getRangeToExtract(context); + const { info } = getRangeToExtract(context); Debug.assert(info && !isRefactorErrorInfo(info), "Expected to find a range to extract"); const name = getUniqueName("NewType", file); @@ -171,20 +175,20 @@ interface InterfaceInfo { type ExtractInfo = TypeAliasInfo | InterfaceInfo; -function getRangeToExtract(context: RefactorContext, considerEmptySpans = true): ExtractInfo | RefactorErrorInfo | undefined { +function getRangeToExtract(context: RefactorContext, considerEmptySpans = true): { info: ExtractInfo | RefactorErrorInfo | undefined; affectedTextRange?: TextRange; } { const { file, startPosition } = context; const isJS = isSourceFileJS(file); const range = createTextRangeFromSpan(getRefactorContextSpan(context)); const isCursorRequest = range.pos === range.end && considerEmptySpans; const firstType = getFirstTypeAt(file, startPosition, range, isCursorRequest); - if (!firstType || !isTypeNode(firstType)) return { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) }; + if (!firstType || !isTypeNode(firstType)) return { info: { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) }, affectedTextRange: undefined }; const checker = context.program.getTypeChecker(); const enclosingNode = getEnclosingNode(firstType, isJS); - if (enclosingNode === undefined) return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }; + if (enclosingNode === undefined) return { info: { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }, affectedTextRange: undefined }; const expandedFirstType = getExpandedSelectionNode(firstType, enclosingNode); - if (!isTypeNode(expandedFirstType)) return { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) }; + if (!isTypeNode(expandedFirstType)) return { info: { error: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_type_node) }, affectedTextRange: undefined }; const typeList: TypeNode[] = []; if ((isUnionTypeNode(expandedFirstType.parent) || isIntersectionTypeNode(expandedFirstType.parent)) && range.end > firstType.end) { @@ -198,11 +202,11 @@ function getRangeToExtract(context: RefactorContext, considerEmptySpans = true): } const selection = typeList.length > 1 ? typeList : expandedFirstType; - const typeParameters = collectTypeParameters(checker, selection, enclosingNode, file); - if (!typeParameters) return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }; + const { typeParameters, affectedTextRange } = collectTypeParameters(checker, selection, enclosingNode, file); + if (!typeParameters) return { info: { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) }, affectedTextRange: undefined }; const typeElements = flattenTypeLiteralNodeReference(checker, selection); - return { isJS, selection, enclosingNode, typeParameters, typeElements }; + return { info: { isJS, selection, enclosingNode, typeParameters, typeElements }, affectedTextRange }; } function getFirstTypeAt(file: SourceFile, startPosition: number, range: TextRange, isCursorRequest: boolean): Node | undefined { @@ -260,14 +264,14 @@ function rangeContainsSkipTrivia(r1: TextRange, node: TextRange, file: SourceFil return rangeContainsStartEnd(r1, skipTrivia(file.text, node.pos), node.end); } -function collectTypeParameters(checker: TypeChecker, selection: TypeNode | TypeNode[], enclosingNode: Node, file: SourceFile): TypeParameterDeclaration[] | undefined { +function collectTypeParameters(checker: TypeChecker, selection: TypeNode | TypeNode[], enclosingNode: Node, file: SourceFile): { typeParameters: TypeParameterDeclaration[] | undefined; affectedTextRange: TextRange | undefined; } { const result: TypeParameterDeclaration[] = []; const selectionArray = toArray(selection); const selectionRange = { pos: selectionArray[0].pos, end: selectionArray[selectionArray.length - 1].end }; for (const t of selectionArray) { - if (visitor(t)) return undefined; + if (visitor(t)) return { typeParameters: undefined, affectedTextRange: undefined }; } - return result; + return { typeParameters: result, affectedTextRange: selectionRange }; function visitor(node: Node): true | undefined { if (isTypeReferenceNode(node)) { diff --git a/src/services/refactors/moveToFile.ts b/src/services/refactors/moveToFile.ts index 36c41a67312bb..a3ac9d9e4bde9 100644 --- a/src/services/refactors/moveToFile.ts +++ b/src/services/refactors/moveToFile.ts @@ -178,7 +178,8 @@ registerRefactor(refactorNameForMoveToFile, { } } if (context.preferences.allowTextChangesInNewFiles && statements) { - return [{ name: refactorNameForMoveToFile, description, actions: [moveToFileAction] }]; + const affectedTextRange = { start: statements.all[0].pos, length: statements.all.length > 1 ? last(statements.all).end - statements.all[0].pos : statements.all[0].end - statements.all[0].pos }; + return [{ name: refactorNameForMoveToFile, description, actions: [{ ...moveToFileAction, range: affectedTextRange }] }]; } if (context.preferences.provideRefactorNotApplicableReason) { return [{ name: refactorNameForMoveToFile, description, actions: [{ ...moveToFileAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_statement_or_statements) }] }]; diff --git a/src/services/refactors/moveToNewFile.ts b/src/services/refactors/moveToNewFile.ts index d2cb36084499c..8f0d11fbd15fe 100644 --- a/src/services/refactors/moveToNewFile.ts +++ b/src/services/refactors/moveToNewFile.ts @@ -14,6 +14,7 @@ import { insertImports, isPrologueDirective, LanguageServiceHost, + last, ModifierFlags, nodeSeenTracker, Program, @@ -64,7 +65,8 @@ registerRefactor(refactorName, { getAvailableActions: function getRefactorActionsToMoveToNewFile(context): readonly ApplicableRefactorInfo[] { const statements = getStatementsToMove(context); if (context.preferences.allowTextChangesInNewFiles && statements) { - return [{ name: refactorName, description, actions: [moveToNewFileAction] }]; + const affectedTextRange = { start: statements.all[0].pos, length: statements.all.length > 1 ? last(statements.all).end - statements.all[0].pos : statements.all[0].end - statements.all[0].pos }; + return [{ name: refactorName, description, actions: [{ ...moveToNewFileAction, range: affectedTextRange }] }]; } if (context.preferences.provideRefactorNotApplicableReason) { return [{ name: refactorName, description, actions: [{ ...moveToNewFileAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_statement_or_statements) }] }]; diff --git a/src/services/types.ts b/src/services/types.ts index 33ed3ede6baca..6221754a300d9 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -1019,6 +1019,11 @@ export interface RefactorActionInfo { * when calling `getEditsForRefactor`. */ isInteractive?: boolean; + + /** + * Range of code the refactoring will be applied to. + */ + range?: TextSpan; } /** diff --git a/src/testRunner/unittests/tsserver/getApplicableRefactors.ts b/src/testRunner/unittests/tsserver/getApplicableRefactors.ts index 6ee8a48be6ce7..92cbc2b0abd49 100644 --- a/src/testRunner/unittests/tsserver/getApplicableRefactors.ts +++ b/src/testRunner/unittests/tsserver/getApplicableRefactors.ts @@ -21,4 +21,69 @@ describe("unittests:: tsserver:: getApplicableRefactors", () => { }); baselineTsserverLogs("getApplicableRefactors", "works when taking position", session); }); + + it("returns the affected range of text for extract symbol refactor", () => { + const file1: File = { + path: "/a.ts", + content: `class Foo { + someMethod(m: number) { + var x = m; + x = x * 3; + var y = 30; + var j = 10; + var z = y + j; + console.log(z); + var q = 10; + return q; + } +}`, + }; + const host = createServerHost([file1]); + const session = new TestSession(host); + openFilesForSession([file1], session); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.GetApplicableRefactors, + arguments: { file: file1.path, startLine: 3, startOffset: 9, endLine: 5, endOffset: 20 }, + }); + baselineTsserverLogs("getApplicableRefactors", "returns the affected range of text for extract symbol refactor", session); + }); + + it("returns the affected range of text for extract type refactor", () => { + const file1: File = { + path: "/a.ts", + content: `type A = Partial & D | C;`, + }; + const host = createServerHost([file1]); + const session = new TestSession(host); + openFilesForSession([file1], session); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.GetApplicableRefactors, + arguments: { file: file1.path, startLine: 1, startOffset: 26, endLine: 1, endOffset: 38 }, + }); + baselineTsserverLogs("getApplicableRefactors", "returns the affected range of text for extract type refactor", session); + }); + + it("returns the affected range of text for 'move to file' and 'move to new file' refactors", () => { + const file1: File = { + path: "/a.ts", + content: `const a = 1; +const b = 1; +function foo() { }`, + }; + const host = createServerHost([file1]); + const session = new TestSession(host); + openFilesForSession([file1], session); + + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.Configure, + arguments: { + preferences: { allowTextChangesInNewFiles: true }, + }, + }); + session.executeCommandSeq({ + command: ts.server.protocol.CommandTypes.GetApplicableRefactors, + arguments: { file: file1.path, startLine: 1, startOffset: 3, endLine: 2, endOffset: 3, includeInteractiveActions: true }, + }); + baselineTsserverLogs("getApplicableRefactors", "returns the affected range of text for 'move to file' and 'move to new file' refactors", session); + }); }); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index dbcb4cf3d7f28..76ade2ea1fd91 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -618,6 +618,10 @@ declare namespace ts { * when calling 'GetEditsForRefactor'. */ isInteractive?: boolean; + /** + * Range of code the refactoring will be applied to. + */ + range?: TextSpan; } interface GetEditsForRefactorRequest extends Request { command: CommandTypes.GetEditsForRefactor; @@ -10972,6 +10976,10 @@ declare namespace ts { * when calling `getEditsForRefactor`. */ isInteractive?: boolean; + /** + * Range of code the refactoring will be applied to. + */ + range?: TextSpan; } /** * A set of edits to make in response to a refactor action, plus an optional diff --git a/tests/baselines/reference/tsserver/fourslashServer/fixExtractToInnerFunctionDuplicaton.js b/tests/baselines/reference/tsserver/fourslashServer/fixExtractToInnerFunctionDuplicaton.js index aa50b4634e62c..96656bf3bacbb 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/fixExtractToInnerFunctionDuplicaton.js +++ b/tests/baselines/reference/tsserver/fourslashServer/fixExtractToInnerFunctionDuplicaton.js @@ -156,12 +156,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to inner function in function 'foo'", "name": "function_scope_0", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to function in global scope", "name": "function_scope_1", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] }, @@ -172,12 +192,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to constant in enclosing scope", "name": "constant_scope_0", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to constant in global scope", "name": "constant_scope_1", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] } @@ -246,12 +286,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to inner function in function 'foo'", "name": "function_scope_0", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to function in global scope", "name": "function_scope_1", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] }, @@ -262,12 +322,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to constant in enclosing scope", "name": "constant_scope_0", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to constant in global scope", "name": "constant_scope_1", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] } @@ -336,12 +416,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to inner function in function 'foo'", "name": "function_scope_0", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to function in global scope", "name": "function_scope_1", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] }, @@ -352,12 +452,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to constant in enclosing scope", "name": "constant_scope_0", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to constant in global scope", "name": "constant_scope_1", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] } @@ -426,12 +546,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to inner function in function 'foo'", "name": "function_scope_0", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to function in global scope", "name": "function_scope_1", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] }, @@ -442,12 +582,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to constant in enclosing scope", "name": "constant_scope_0", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to constant in global scope", "name": "constant_scope_1", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] } @@ -516,12 +676,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to inner function in function 'foo'", "name": "function_scope_0", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to function in global scope", "name": "function_scope_1", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] }, @@ -532,12 +712,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to constant in enclosing scope", "name": "constant_scope_0", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to constant in global scope", "name": "constant_scope_1", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] } @@ -606,12 +806,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to inner function in function 'foo'", "name": "function_scope_0", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to function in global scope", "name": "function_scope_1", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] }, @@ -622,12 +842,32 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to constant in enclosing scope", "name": "constant_scope_0", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } }, { "description": "Extract to constant in global scope", "name": "constant_scope_1", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 24 + }, + "end": { + "line": 1, + "offset": 41 + } + } } ] } diff --git a/tests/baselines/reference/tsserver/fourslashServer/moveToFile_emptyTargetFile.js b/tests/baselines/reference/tsserver/fourslashServer/moveToFile_emptyTargetFile.js index 0a364963050f6..5414c78b40e24 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/moveToFile_emptyTargetFile.js +++ b/tests/baselines/reference/tsserver/fourslashServer/moveToFile_emptyTargetFile.js @@ -248,7 +248,17 @@ Info seq [hh:mm:ss:mss] response: { "name": "Move to a new file", "description": "Move to a new file", - "kind": "refactor.move.newFile" + "kind": "refactor.move.newFile", + "range": { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 20 + } + } } ] }, @@ -259,7 +269,17 @@ Info seq [hh:mm:ss:mss] response: { "name": "Move to file", "description": "Move to file", - "kind": "refactor.move.file" + "kind": "refactor.move.file", + "range": { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 1, + "offset": 20 + } + } } ] }, @@ -270,7 +290,17 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to function in module scope", "name": "function_scope_0", - "kind": "refactor.extract.function" + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 1, + "offset": 17 + }, + "end": { + "line": 1, + "offset": 19 + } + } } ] }, @@ -281,7 +311,17 @@ Info seq [hh:mm:ss:mss] response: { "description": "Extract to constant in enclosing scope", "name": "constant_scope_0", - "kind": "refactor.extract.constant" + "kind": "refactor.extract.constant", + "range": { + "start": { + "line": 1, + "offset": 17 + }, + "end": { + "line": 1, + "offset": 19 + } + } } ] } diff --git a/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-'move-to-file'-and-'move-to-new-file'-refactors.js b/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-'move-to-file'-and-'move-to-new-file'-refactors.js new file mode 100644 index 0000000000000..963e2a025f6b4 --- /dev/null +++ b/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-'move-to-file'-and-'move-to-new-file'-refactors.js @@ -0,0 +1,155 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +Before request +//// [/a.ts] +const a = 1; +const b = 1; +function foo() { } + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "/a.ts" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /a.ts :: No config files found. +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /dev/null/inferredProject1* WatchType: Missing file +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (1) + /a.ts SVC-1-0 "const a = 1;\nconst b = 1;\nfunction foo() { }" + + + a.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (1) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /a.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +PolledWatches:: +/a/lib/lib.d.ts: *new* + {"pollingInterval":500} + +Projects:: +/dev/null/inferredProject1* (Inferred) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/a.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /dev/null/inferredProject1* *default* + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "configure", + "arguments": { + "preferences": { + "allowTextChangesInNewFiles": true + } + }, + "seq": 2, + "type": "request" + } +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 2, + "success": true, + "performanceData": { + "updateGraphDurationMs": * + } + } +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "getApplicableRefactors", + "arguments": { + "file": "/a.ts", + "startLine": 1, + "startOffset": 3, + "endLine": 2, + "endOffset": 3, + "includeInteractiveActions": true + }, + "seq": 3, + "type": "request" + } +Info seq [hh:mm:ss:mss] response: + { + "response": [ + { + "name": "Move to a new file", + "description": "Move to a new file", + "actions": [ + { + "name": "Move to a new file", + "description": "Move to a new file", + "kind": "refactor.move.newFile", + "range": { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 13 + } + } + } + ] + }, + { + "name": "Move to file", + "description": "Move to file", + "actions": [ + { + "name": "Move to file", + "description": "Move to file", + "kind": "refactor.move.file", + "range": { + "start": { + "line": 1, + "offset": 1 + }, + "end": { + "line": 2, + "offset": 13 + } + } + } + ] + } + ], + "responseRequired": true + } +After request diff --git a/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-extract-symbol-refactor.js b/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-extract-symbol-refactor.js new file mode 100644 index 0000000000000..ac7ee1c4c179a --- /dev/null +++ b/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-extract-symbol-refactor.js @@ -0,0 +1,142 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +Before request +//// [/a.ts] +class Foo { + someMethod(m: number) { + var x = m; + x = x * 3; + var y = 30; + var j = 10; + var z = y + j; + console.log(z); + var q = 10; + return q; + } +} + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "/a.ts" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /a.ts :: No config files found. +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /dev/null/inferredProject1* WatchType: Missing file +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (1) + /a.ts SVC-1-0 "class Foo {\n someMethod(m: number) {\n var x = m;\n x = x * 3;\n var y = 30;\n var j = 10;\n var z = y + j;\n console.log(z);\n var q = 10;\n return q;\n }\n}" + + + a.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (1) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /a.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +PolledWatches:: +/a/lib/lib.d.ts: *new* + {"pollingInterval":500} + +Projects:: +/dev/null/inferredProject1* (Inferred) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/a.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /dev/null/inferredProject1* *default* + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "getApplicableRefactors", + "arguments": { + "file": "/a.ts", + "startLine": 3, + "startOffset": 9, + "endLine": 5, + "endOffset": 20 + }, + "seq": 2, + "type": "request" + } +Info seq [hh:mm:ss:mss] response: + { + "response": [ + { + "name": "Extract Symbol", + "description": "Extract function", + "actions": [ + { + "description": "Extract to inner function in method 'someMethod'", + "name": "function_scope_0", + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 3, + "offset": 9 + }, + "end": { + "line": 5, + "offset": 20 + } + } + }, + { + "description": "Extract to method in class 'Foo'", + "name": "function_scope_1", + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 3, + "offset": 9 + }, + "end": { + "line": 5, + "offset": 20 + } + } + }, + { + "description": "Extract to function in global scope", + "name": "function_scope_2", + "kind": "refactor.extract.function", + "range": { + "start": { + "line": 3, + "offset": 9 + }, + "end": { + "line": 5, + "offset": 20 + } + } + } + ] + } + ], + "responseRequired": true + } +After request diff --git a/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-extract-type-refactor.js b/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-extract-type-refactor.js new file mode 100644 index 0000000000000..7fb510f79d0f5 --- /dev/null +++ b/tests/baselines/reference/tsserver/getApplicableRefactors/returns-the-affected-range-of-text-for-extract-type-refactor.js @@ -0,0 +1,101 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +Before request +//// [/a.ts] +type A = Partial & D | C; + + +Info seq [hh:mm:ss:mss] request: + { + "command": "open", + "arguments": { + "file": "/a.ts" + }, + "seq": 1, + "type": "request" + } +Info seq [hh:mm:ss:mss] Search path: / +Info seq [hh:mm:ss:mss] For info: /a.ts :: No config files found. +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /dev/null/inferredProject1* WatchType: Missing file +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* projectStateVersion: 1 projectProgramVersion: 0 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (1) + /a.ts SVC-1-0 "type A = Partial & D | C;" + + + a.ts + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (1) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /a.ts ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] response: + { + "responseRequired": false + } +After request + +PolledWatches:: +/a/lib/lib.d.ts: *new* + {"pollingInterval":500} + +Projects:: +/dev/null/inferredProject1* (Inferred) *new* + projectStateVersion: 1 + projectProgramVersion: 1 + +ScriptInfos:: +/a.ts (Open) *new* + version: SVC-1-0 + containingProjects: 1 + /dev/null/inferredProject1* *default* + +Before request + +Info seq [hh:mm:ss:mss] request: + { + "command": "getApplicableRefactors", + "arguments": { + "file": "/a.ts", + "startLine": 1, + "startOffset": 26, + "endLine": 1, + "endOffset": 38 + }, + "seq": 2, + "type": "request" + } +Info seq [hh:mm:ss:mss] response: + { + "response": [ + { + "name": "Extract type", + "description": "Extract type", + "actions": [ + { + "name": "Extract to type alias", + "description": "Extract to type alias", + "kind": "refactor.extract.type", + "range": { + "start": { + "line": 1, + "offset": 22 + }, + "end": { + "line": 1, + "offset": 46 + } + } + } + ] + } + ], + "responseRequired": true + } +After request