From dbeae5d943c784661862c52b8e215a2907c31a33 Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Fri, 7 Oct 2022 19:13:22 +0300 Subject: [PATCH] fix(51017): Make lineText in the references response opt-out (#51081) * add option to exclude lineText from the response * add comments * update baseline --- src/server/protocol.ts | 17 ++++++++++---- src/server/session.ts | 16 +++++++++---- .../unittests/tsserver/getFileReferences.ts | 23 +++++++++++++++++++ src/testRunner/unittests/tsserver/helpers.ts | 2 +- .../reference/api/tsserverlibrary.d.ts | 16 +++++++++---- 5 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 372898c4aff73..e4d4a2e2d625f 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -1158,12 +1158,14 @@ namespace ts.server.protocol { } export interface ReferencesResponseItem extends FileSpanWithContext { - /** Text of line containing the reference. Including this - * with the response avoids latency of editor loading files - * to show text of reference line (the server already has - * loaded the referencing files). + /** + * Text of line containing the reference. Including this + * with the response avoids latency of editor loading files + * to show text of reference line (the server already has loaded the referencing files). + * + * If {@link UserPreferences.disableLineTextInReferences} is enabled, the property won't be filled */ - lineText: string; + lineText?: string; /** * True if reference is a write location, false otherwise. @@ -3478,6 +3480,11 @@ namespace ts.server.protocol { readonly includeInlayFunctionLikeReturnTypeHints?: boolean; readonly includeInlayEnumMemberValueHints?: boolean; readonly autoImportFileExcludePatterns?: string[]; + + /** + * Indicates whether {@link ReferencesResponseItem.lineText} is supported. + */ + readonly disableLineTextInReferences?: boolean; } export interface CompilerOptions { diff --git a/src/server/session.ts b/src/server/session.ts index 302884cf0801c..8e63f93556dba 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1807,6 +1807,7 @@ namespace ts.server { if (!simplifiedResult) return references; + const preferences = this.getPreferences(file); const defaultProject = this.getDefaultProject(args); const scriptInfo = defaultProject.getScriptInfoForNormalizedPath(file)!; const nameInfo = defaultProject.getLanguageService().getQuickInfoAtPosition(file, position); @@ -1815,7 +1816,7 @@ namespace ts.server { const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0; const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : ""; const refs: readonly protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol => { - return referencedSymbol.references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry)); + return referencedSymbol.references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences)); }); return { refs, symbolName, symbolStartOffset, symbolDisplayString }; } @@ -1823,6 +1824,7 @@ namespace ts.server { private getFileReferences(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.FileReferencesResponseBody | readonly ReferenceEntry[] { const projects = this.getProjects(args); const fileName = args.file; + const preferences = this.getPreferences(toNormalizedPath(fileName)); const references: ReferenceEntry[] = []; const seen = createDocumentSpanSet(); @@ -1842,7 +1844,7 @@ namespace ts.server { }); if (!simplifiedResult) return references; - const refs = references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry)); + const refs = references.map(entry => referenceEntryToReferencesResponseItem(this.projectService, entry, preferences)); return { refs, symbolName: `"${args.file}"` @@ -3516,11 +3518,10 @@ namespace ts.server { return text; } - function referenceEntryToReferencesResponseItem(projectService: ProjectService, { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferencedSymbolEntry): protocol.ReferencesResponseItem { + function referenceEntryToReferencesResponseItem(projectService: ProjectService, { fileName, textSpan, contextSpan, isWriteAccess, isDefinition }: ReferencedSymbolEntry, { disableLineTextInReferences }: protocol.UserPreferences): protocol.ReferencesResponseItem { const scriptInfo = Debug.checkDefined(projectService.getScriptInfo(fileName)); const span = toProtocolTextSpanWithContext(textSpan, contextSpan, scriptInfo); - const lineSpan = scriptInfo.lineToTextSpan(span.start.line - 1); - const lineText = scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, ""); + const lineText = disableLineTextInReferences ? undefined : getLineText(scriptInfo, span); return { file: fileName, ...span, @@ -3530,6 +3531,11 @@ namespace ts.server { }; } + function getLineText(scriptInfo: ScriptInfo, span: protocol.TextSpanWithContext) { + const lineSpan = scriptInfo.lineToTextSpan(span.start.line - 1); + return scriptInfo.getSnapshot().getText(lineSpan.start, textSpanEnd(lineSpan)).replace(/\r|\n/g, ""); + } + function isCompletionEntryData(data: any): data is CompletionEntryData { return data === undefined || data && typeof data === "object" && typeof data.exportName === "string" diff --git a/src/testRunner/unittests/tsserver/getFileReferences.ts b/src/testRunner/unittests/tsserver/getFileReferences.ts index 4244671e756c4..7e1f9cc8de49a 100644 --- a/src/testRunner/unittests/tsserver/getFileReferences.ts +++ b/src/testRunner/unittests/tsserver/getFileReferences.ts @@ -54,5 +54,28 @@ namespace ts.projectSystem { assert.deepEqual(response, expectResponse); }); + + it("should skip lineText from file references", () => { + const session = makeSampleSession(); + session.getProjectService().setHostConfiguration({ preferences: { disableLineTextInReferences: true } }); + + const response = executeSessionRequest( + session, + protocol.CommandTypes.FileReferences, + { file: aTs.path }, + ); + + const expectResponse: protocol.FileReferencesResponseBody = { + refs: [ + makeReferenceItem({ file: bTs, text: "./a", lineText: undefined, contextText: importA, isWriteAccess: false }), + makeReferenceItem({ file: cTs, text: "./a", lineText: undefined, contextText: importCurlyFromA, isWriteAccess: false }), + makeReferenceItem({ file: dTs, text: "/project/a", lineText: undefined, contextText: importAFromA, isWriteAccess: false }), + makeReferenceItem({ file: dTs, text: "./a", lineText: undefined, contextText: typeofImportA, isWriteAccess: false }), + ], + symbolName: `"${aTs.path}"`, + }; + + assert.deepEqual(response, expectResponse); + }); }); } diff --git a/src/testRunner/unittests/tsserver/helpers.ts b/src/testRunner/unittests/tsserver/helpers.ts index 17b449b8459ea..a51a558732142 100644 --- a/src/testRunner/unittests/tsserver/helpers.ts +++ b/src/testRunner/unittests/tsserver/helpers.ts @@ -810,7 +810,7 @@ namespace ts.projectSystem { export interface MakeReferenceItem extends DocumentSpanFromSubstring { isDefinition?: boolean; isWriteAccess?: boolean; - lineText: string; + lineText?: string; } export function makeReferenceItem({ isDefinition, isWriteAccess, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 76ad8dbfe7ecb..90dd9ed780fd0 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -7982,12 +7982,14 @@ declare namespace ts.server.protocol { command: CommandTypes.References; } interface ReferencesResponseItem extends FileSpanWithContext { - /** Text of line containing the reference. Including this - * with the response avoids latency of editor loading files - * to show text of reference line (the server already has - * loaded the referencing files). + /** + * Text of line containing the reference. Including this + * with the response avoids latency of editor loading files + * to show text of reference line (the server already has loaded the referencing files). + * + * If {@link UserPreferences.disableLineTextInReferences} is enabled, the property won't be filled */ - lineText: string; + lineText?: string; /** * True if reference is a write location, false otherwise. */ @@ -9833,6 +9835,10 @@ declare namespace ts.server.protocol { readonly includeInlayFunctionLikeReturnTypeHints?: boolean; readonly includeInlayEnumMemberValueHints?: boolean; readonly autoImportFileExcludePatterns?: string[]; + /** + * Indicates whether {@link ReferencesResponseItem.lineText} is supported. + */ + readonly disableLineTextInReferences?: boolean; } interface CompilerOptions { allowJs?: boolean;