mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Porting https://github.com/Microsoft/TypeScript/pull/29314 to release-3.3
This commit is contained in:
committed by
GitHub
parent
49689894d7
commit
8680908150
@@ -5864,6 +5864,7 @@ namespace ts {
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly providePrefixAndSuffixTextForRename?: boolean;
|
||||
}
|
||||
|
||||
/** Represents a bigint literal value without requiring bigint support */
|
||||
|
||||
@@ -1170,7 +1170,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
public verifyRenameLocations(startRanges: ArrayOrSingle<Range>, options: FourSlashInterface.RenameLocationsOptions) {
|
||||
const { findInStrings = false, findInComments = false, ranges = this.getRanges() } = ts.isArray(options) ? { findInStrings: false, findInComments: false, ranges: options } : options;
|
||||
const { findInStrings = false, findInComments = false, ranges = this.getRanges(), providePrefixAndSuffixTextForRename = true } = ts.isArray(options) ? { findInStrings: false, findInComments: false, ranges: options, providePrefixAndSuffixTextForRename: true } : options;
|
||||
|
||||
for (const startRange of toArray(startRanges)) {
|
||||
this.goToRangeStart(startRange);
|
||||
@@ -1182,7 +1182,7 @@ Actual: ${stringify(fullActual)}`);
|
||||
}
|
||||
|
||||
const references = this.languageService.findRenameLocations(
|
||||
this.activeFile.fileName, this.currentCaretPosition, findInStrings, findInComments);
|
||||
this.activeFile.fileName, this.currentCaretPosition, findInStrings, findInComments, providePrefixAndSuffixTextForRename);
|
||||
|
||||
const sort = (locations: ReadonlyArray<ts.RenameLocation> | undefined) =>
|
||||
locations && ts.sort(locations, (r1, r2) => ts.compareStringsCaseSensitive(r1.fileName, r2.fileName) || r1.textSpan.start - r2.textSpan.start);
|
||||
@@ -5087,6 +5087,7 @@ namespace FourSlashInterface {
|
||||
readonly findInStrings?: boolean;
|
||||
readonly findInComments?: boolean;
|
||||
readonly ranges: ReadonlyArray<RenameLocationOptions>;
|
||||
readonly providePrefixAndSuffixTextForRename?: boolean;
|
||||
};
|
||||
export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range, readonly prefixText?: string, readonly suffixText?: string };
|
||||
}
|
||||
|
||||
@@ -472,8 +472,8 @@ namespace Harness.LanguageService {
|
||||
getRenameInfo(fileName: string, position: number, options?: ts.RenameInfoOptions): ts.RenameInfo {
|
||||
return unwrapJSONCallResult(this.shim.getRenameInfo(fileName, position, options));
|
||||
}
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ts.RenameLocation[] {
|
||||
return unwrapJSONCallResult(this.shim.findRenameLocations(fileName, position, findInStrings, findInComments));
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ts.RenameLocation[] {
|
||||
return unwrapJSONCallResult(this.shim.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename));
|
||||
}
|
||||
getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] {
|
||||
return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position));
|
||||
|
||||
@@ -2906,6 +2906,7 @@ namespace ts.server.protocol {
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
readonly allowRenameOfImportPath?: boolean;
|
||||
readonly providePrefixAndSuffixTextForRename?: boolean;
|
||||
}
|
||||
|
||||
export interface CompilerOptions {
|
||||
|
||||
@@ -314,7 +314,8 @@ namespace ts.server {
|
||||
defaultProject: Project,
|
||||
initialLocation: DocumentPosition,
|
||||
findInStrings: boolean,
|
||||
findInComments: boolean
|
||||
findInComments: boolean,
|
||||
hostPreferences: UserPreferences
|
||||
): ReadonlyArray<RenameLocation> {
|
||||
const outputs: RenameLocation[] = [];
|
||||
|
||||
@@ -323,7 +324,7 @@ namespace ts.server {
|
||||
defaultProject,
|
||||
initialLocation,
|
||||
({ project, location }, tryAddToTodo) => {
|
||||
for (const output of project.getLanguageService().findRenameLocations(location.fileName, location.pos, findInStrings, findInComments) || emptyArray) {
|
||||
for (const output of project.getLanguageService().findRenameLocations(location.fileName, location.pos, findInStrings, findInComments, hostPreferences.providePrefixAndSuffixTextForRename) || emptyArray) {
|
||||
if (!contains(outputs, output, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(output))) {
|
||||
outputs.push(output);
|
||||
}
|
||||
@@ -1232,7 +1233,8 @@ namespace ts.server {
|
||||
this.getDefaultProject(args),
|
||||
{ fileName: args.file, pos: position },
|
||||
!!args.findInStrings,
|
||||
!!args.findInComments
|
||||
!!args.findInComments,
|
||||
this.getHostPreferences()
|
||||
);
|
||||
if (!simplifiedResult) return locations;
|
||||
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace ts.FindAllReferences {
|
||||
readonly isForRename?: boolean;
|
||||
/** True if we are searching for implementations. We will have a different method of adding references if so. */
|
||||
readonly implementations?: boolean;
|
||||
/**
|
||||
* True to opt in for enhanced renaming of shorthand properties and import/export specifiers.
|
||||
* Default is false for backwards compatibility.
|
||||
*/
|
||||
readonly providePrefixAndSuffixTextForRename?: boolean;
|
||||
}
|
||||
|
||||
export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined {
|
||||
@@ -157,8 +162,8 @@ namespace ts.FindAllReferences {
|
||||
return { displayParts, kind: symbolKind };
|
||||
}
|
||||
|
||||
export function toRenameLocation(entry: Entry, originalNode: Node, checker: TypeChecker): RenameLocation {
|
||||
return { ...entryToDocumentSpan(entry), ...getPrefixAndSuffixText(entry, originalNode, checker) };
|
||||
export function toRenameLocation(entry: Entry, originalNode: Node, checker: TypeChecker, providePrefixAndSuffixText: boolean): RenameLocation {
|
||||
return { ...entryToDocumentSpan(entry), ...(providePrefixAndSuffixText && getPrefixAndSuffixText(entry, originalNode, checker)) };
|
||||
}
|
||||
|
||||
export function toReferenceEntry(entry: Entry): ReferenceEntry {
|
||||
@@ -484,7 +489,7 @@ namespace ts.FindAllReferences.Core {
|
||||
|
||||
/** Core find-all-references algorithm for a normal symbol. */
|
||||
function getReferencedSymbolsForSymbol(originalSymbol: Symbol, node: Node | undefined, sourceFiles: ReadonlyArray<SourceFile>, sourceFilesSet: ReadonlyMap<true>, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] {
|
||||
const symbol = node && skipPastExportOrImportSpecifierOrUnion(originalSymbol, node, checker, !!options.isForRename) || originalSymbol;
|
||||
const symbol = node && skipPastExportOrImportSpecifierOrUnion(originalSymbol, node, checker, /*useLocalSymbolForExportSpecifier*/ !isForRenameWithPrefixAndSuffixText(options)) || originalSymbol;
|
||||
|
||||
// Compute the meaning from the location and the symbol it references
|
||||
const searchMeaning = node ? getIntersectingMeaningFromDeclarations(node, symbol) : SemanticMeaning.All;
|
||||
@@ -492,7 +497,7 @@ namespace ts.FindAllReferences.Core {
|
||||
const result: SymbolAndEntries[] = [];
|
||||
const state = new State(sourceFiles, sourceFilesSet, node ? getSpecialSearchKind(node) : SpecialSearchKind.None, checker, cancellationToken, searchMeaning, options, result);
|
||||
|
||||
const exportSpecifier = !options.isForRename ? undefined : find(symbol.declarations, isExportSpecifier);
|
||||
const exportSpecifier = !isForRenameWithPrefixAndSuffixText(options) ? undefined : find(symbol.declarations, isExportSpecifier);
|
||||
if (exportSpecifier) {
|
||||
// When renaming at an export specifier, rename the export and not the thing being exported.
|
||||
getReferencesAtExportSpecifier(exportSpecifier.name, symbol, exportSpecifier, state.createSearch(node, originalSymbol, /*comingFrom*/ undefined), state, /*addReferencesHere*/ true, /*alwaysGetReferences*/ true);
|
||||
@@ -502,7 +507,7 @@ namespace ts.FindAllReferences.Core {
|
||||
searchForImportsOfExport(node, symbol, { exportingModuleSymbol: Debug.assertDefined(symbol.parent, "Expected export symbol to have a parent"), exportKind: ExportKind.Default }, state);
|
||||
}
|
||||
else {
|
||||
const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, !!options.isForRename, !!options.implementations) : [symbol] });
|
||||
const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, !!options.isForRename, !!options.providePrefixAndSuffixTextForRename, !!options.implementations) : [symbol] });
|
||||
|
||||
// Try to get the smallest valid scope that we can limit our search to;
|
||||
// otherwise we'll need to search globally (i.e. include each file).
|
||||
@@ -538,9 +543,9 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
/** Handle a few special cases relating to export/import specifiers. */
|
||||
function skipPastExportOrImportSpecifierOrUnion(symbol: Symbol, node: Node, checker: TypeChecker, isForRename: boolean): Symbol | undefined {
|
||||
function skipPastExportOrImportSpecifierOrUnion(symbol: Symbol, node: Node, checker: TypeChecker, useLocalSymbolForExportSpecifier: boolean): Symbol | undefined {
|
||||
const { parent } = node;
|
||||
if (isExportSpecifier(parent) && !isForRename) {
|
||||
if (isExportSpecifier(parent) && useLocalSymbolForExportSpecifier) {
|
||||
return getLocalSymbolForExportSpecifier(node as Identifier, symbol, parent, checker);
|
||||
}
|
||||
// If the symbol is declared as part of a declaration like `{ type: "a" } | { type: "b" }`, use the property on the union type to get more references.
|
||||
@@ -1071,6 +1076,8 @@ namespace ts.FindAllReferences.Core {
|
||||
addReferencesHere: boolean,
|
||||
alwaysGetReferences?: boolean,
|
||||
): void {
|
||||
Debug.assert(!alwaysGetReferences || !!state.options.providePrefixAndSuffixTextForRename, "If alwaysGetReferences is true, then prefix/suffix text must be enabled");
|
||||
|
||||
const { parent, propertyName, name } = exportSpecifier;
|
||||
const exportDeclaration = parent.parent;
|
||||
const localSymbol = getLocalSymbolForExportSpecifier(referenceLocation, referenceSymbol, exportSpecifier, state.checker);
|
||||
@@ -1102,7 +1109,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
// For `export { foo as bar }`, rename `foo`, but not `bar`.
|
||||
if (!state.options.isForRename || alwaysGetReferences) {
|
||||
if (!isForRenameWithPrefixAndSuffixText(state.options) || alwaysGetReferences) {
|
||||
const exportKind = referenceLocation.originalKeywordKind === SyntaxKind.DefaultKeyword ? ExportKind.Default : ExportKind.Named;
|
||||
const exportSymbol = Debug.assertDefined(exportSpecifier.symbol);
|
||||
const exportInfo = Debug.assertDefined(getExportInfo(exportSymbol, exportKind, state.checker));
|
||||
@@ -1110,7 +1117,7 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
// At `export { x } from "foo"`, also search for the imported symbol `"foo".x`.
|
||||
if (search.comingFrom !== ImportExport.Export && exportDeclaration.moduleSpecifier && !propertyName && !state.options.isForRename) {
|
||||
if (search.comingFrom !== ImportExport.Export && exportDeclaration.moduleSpecifier && !propertyName && !isForRenameWithPrefixAndSuffixText(state.options)) {
|
||||
const imported = state.checker.getExportSpecifierLocalTargetSymbol(exportSpecifier);
|
||||
if (imported) searchForImportedSymbol(imported, state);
|
||||
}
|
||||
@@ -1145,7 +1152,7 @@ namespace ts.FindAllReferences.Core {
|
||||
const { symbol } = importOrExport;
|
||||
|
||||
if (importOrExport.kind === ImportExport.Import) {
|
||||
if (!state.options.isForRename) {
|
||||
if (!(isForRenameWithPrefixAndSuffixText(state.options))) {
|
||||
searchForImportedSymbol(symbol, state);
|
||||
}
|
||||
}
|
||||
@@ -1514,16 +1521,16 @@ namespace ts.FindAllReferences.Core {
|
||||
|
||||
// For certain symbol kinds, we need to include other symbols in the search set.
|
||||
// This is not needed when searching for re-exports.
|
||||
function populateSearchSymbolSet(symbol: Symbol, location: Node, checker: TypeChecker, isForRename: boolean, implementations: boolean): Symbol[] {
|
||||
function populateSearchSymbolSet(symbol: Symbol, location: Node, checker: TypeChecker, isForRename: boolean, providePrefixAndSuffixText: boolean, implementations: boolean): Symbol[] {
|
||||
const result: Symbol[] = [];
|
||||
forEachRelatedSymbol<void>(symbol, location, checker, isForRename,
|
||||
forEachRelatedSymbol<void>(symbol, location, checker, isForRename, !(isForRename && providePrefixAndSuffixText),
|
||||
(sym, root, base) => { result.push(base || root || sym); },
|
||||
/*allowBaseTypes*/ () => !implementations);
|
||||
return result;
|
||||
}
|
||||
|
||||
function forEachRelatedSymbol<T>(
|
||||
symbol: Symbol, location: Node, checker: TypeChecker, isForRenamePopulateSearchSymbolSet: boolean,
|
||||
symbol: Symbol, location: Node, checker: TypeChecker, isForRenamePopulateSearchSymbolSet: boolean, onlyIncludeBindingElementAtReferenceLocation: boolean,
|
||||
cbSymbol: (symbol: Symbol, rootSymbol?: Symbol, baseSymbol?: Symbol, kind?: NodeEntryKind) => T | undefined,
|
||||
allowBaseTypes: (rootSymbol: Symbol) => boolean,
|
||||
): T | undefined {
|
||||
@@ -1577,9 +1584,25 @@ namespace ts.FindAllReferences.Core {
|
||||
}
|
||||
|
||||
// symbolAtLocation for a binding element is the local symbol. See if the search symbol is the property.
|
||||
// Don't do this when populating search set for a rename -- just rename the local.
|
||||
// Don't do this when populating search set for a rename when prefix and suffix text will be provided -- just rename the local.
|
||||
if (!isForRenamePopulateSearchSymbolSet) {
|
||||
const bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName(location.parent) ? getPropertySymbolFromBindingElement(checker, location.parent) : undefined;
|
||||
let bindingElementPropertySymbol: Symbol | undefined;
|
||||
if (onlyIncludeBindingElementAtReferenceLocation) {
|
||||
bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName(location.parent) ? getPropertySymbolFromBindingElement(checker, location.parent) : undefined;
|
||||
}
|
||||
else {
|
||||
bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker);
|
||||
}
|
||||
return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal);
|
||||
}
|
||||
|
||||
Debug.assert(isForRenamePopulateSearchSymbolSet);
|
||||
// due to the above assert and the arguments at the uses of this function,
|
||||
// (onlyIncludeBindingElementAtReferenceLocation <=> !providePrefixAndSuffixTextForRename) holds
|
||||
const includeOriginalSymbolOfBindingElement = onlyIncludeBindingElementAtReferenceLocation;
|
||||
|
||||
if (includeOriginalSymbolOfBindingElement) {
|
||||
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker);
|
||||
return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal);
|
||||
}
|
||||
|
||||
@@ -1597,6 +1620,13 @@ namespace ts.FindAllReferences.Core {
|
||||
? getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker, base => cbSymbol(sym, rootSymbol, base, kind))
|
||||
: undefined));
|
||||
}
|
||||
|
||||
function getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol: Symbol, checker: TypeChecker): Symbol | undefined {
|
||||
const bindingElement = getDeclarationOfKind<BindingElement>(symbol, SyntaxKind.BindingElement);
|
||||
if (bindingElement && isObjectBindingElementWithoutPropertyName(bindingElement)) {
|
||||
return getPropertySymbolFromBindingElement(checker, bindingElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface RelatedSymbol {
|
||||
@@ -1606,6 +1636,7 @@ namespace ts.FindAllReferences.Core {
|
||||
function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): RelatedSymbol | undefined {
|
||||
const { checker } = state;
|
||||
return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker, /*isForRenamePopulateSearchSymbolSet*/ false,
|
||||
/*onlyIncludeBindingElementAtReferenceLocation*/ !state.options.isForRename || !!state.options.providePrefixAndSuffixTextForRename,
|
||||
(sym, rootSymbol, baseSymbol, kind): RelatedSymbol | undefined => search.includes(baseSymbol || rootSymbol || sym)
|
||||
// For a base type, use the symbol for the derived type. For a synthetic (e.g. union) property, use the union symbol.
|
||||
? { symbol: rootSymbol && !(getCheckFlags(sym) & CheckFlags.Synthetic) ? rootSymbol : sym, kind }
|
||||
@@ -1696,4 +1727,8 @@ namespace ts.FindAllReferences.Core {
|
||||
t.symbol && t.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? t.symbol : undefined);
|
||||
return res.length === 0 ? undefined : res;
|
||||
}
|
||||
|
||||
function isForRenameWithPrefixAndSuffixText(options: Options) {
|
||||
return options.isForRename && options.providePrefixAndSuffixTextForRename;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1549,7 +1549,7 @@ namespace ts {
|
||||
return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch);
|
||||
}
|
||||
|
||||
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] | undefined {
|
||||
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): RenameLocation[] | undefined {
|
||||
synchronizeHostData();
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
@@ -1559,7 +1559,8 @@ namespace ts {
|
||||
({ fileName: sourceFile.fileName, textSpan: createTextSpanFromNode(node.tagName, sourceFile) }));
|
||||
}
|
||||
else {
|
||||
return getReferencesWorker(node, position, { findInStrings, findInComments, isForRename: true }, FindAllReferences.toRenameLocation);
|
||||
return getReferencesWorker(node, position, { findInStrings, findInComments, providePrefixAndSuffixTextForRename, isForRename: true },
|
||||
(entry, originalNode, checker) => FindAllReferences.toRenameLocation(entry, originalNode, checker, providePrefixAndSuffixTextForRename || false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace ts {
|
||||
* Returns a JSON-encoded value of the type:
|
||||
* { fileName: string, textSpan: { start: number, length: number } }[]
|
||||
*/
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): string;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): string;
|
||||
|
||||
/**
|
||||
* Returns a JSON-encoded value of the type:
|
||||
@@ -838,10 +838,10 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
public findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): string {
|
||||
public findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): string {
|
||||
return this.forwardJSONCall(
|
||||
`findRenameLocations('${fileName}', ${position}, ${findInStrings}, ${findInComments})`,
|
||||
() => this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments)
|
||||
`findRenameLocations('${fileName}', ${position}, ${findInStrings}, ${findInComments}, ${providePrefixAndSuffixTextForRename})`,
|
||||
() => this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ namespace ts {
|
||||
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
|
||||
|
||||
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReadonlyArray<RenameLocation> | undefined;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ReadonlyArray<RenameLocation> | undefined;
|
||||
|
||||
getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
|
||||
getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined;
|
||||
|
||||
@@ -32,13 +32,39 @@ namespace ts.projectSystem {
|
||||
});
|
||||
});
|
||||
|
||||
it("works with prefixText and suffixText", () => {
|
||||
it("works with prefixText and suffixText when enabled", () => {
|
||||
const aTs: File = { path: "/a.ts", content: "const x = 0; const o = { x };" };
|
||||
const session = createSession(createServerHost([aTs]));
|
||||
const host = createServerHost([aTs]);
|
||||
const session = createSession(host);
|
||||
openFilesForSession([aTs], session);
|
||||
|
||||
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
|
||||
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
|
||||
// rename with prefixText and suffixText disabled
|
||||
const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
|
||||
assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, {
|
||||
info: {
|
||||
canRename: true,
|
||||
fileToRename: undefined,
|
||||
displayName: "x",
|
||||
fullDisplayName: "x",
|
||||
kind: ScriptElementKind.constElement,
|
||||
kindModifiers: ScriptElementKindModifier.none,
|
||||
triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"),
|
||||
},
|
||||
locs: [
|
||||
{
|
||||
file: aTs.path,
|
||||
locs: [
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x"),
|
||||
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 1 }),
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// rename with prefixText and suffixText enabled
|
||||
session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: true } });
|
||||
const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
|
||||
assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, {
|
||||
info: {
|
||||
canRename: true,
|
||||
fileToRename: undefined,
|
||||
|
||||
+3
-1
@@ -3013,6 +3013,7 @@ declare namespace ts {
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly providePrefixAndSuffixTextForRename?: boolean;
|
||||
}
|
||||
/** Represents a bigint literal value without requiring bigint support */
|
||||
interface PseudoBigInt {
|
||||
@@ -4707,7 +4708,7 @@ declare namespace ts {
|
||||
getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined;
|
||||
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
|
||||
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReadonlyArray<RenameLocation> | undefined;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ReadonlyArray<RenameLocation> | undefined;
|
||||
getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
|
||||
getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined;
|
||||
getTypeDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
|
||||
@@ -7927,6 +7928,7 @@ declare namespace ts.server.protocol {
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
readonly allowRenameOfImportPath?: boolean;
|
||||
readonly providePrefixAndSuffixTextForRename?: boolean;
|
||||
}
|
||||
interface CompilerOptions {
|
||||
allowJs?: boolean;
|
||||
|
||||
+2
-1
@@ -3013,6 +3013,7 @@ declare namespace ts {
|
||||
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
|
||||
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
|
||||
readonly allowTextChangesInNewFiles?: boolean;
|
||||
readonly providePrefixAndSuffixTextForRename?: boolean;
|
||||
}
|
||||
/** Represents a bigint literal value without requiring bigint support */
|
||||
interface PseudoBigInt {
|
||||
@@ -4707,7 +4708,7 @@ declare namespace ts {
|
||||
getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined;
|
||||
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
|
||||
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReadonlyArray<RenameLocation> | undefined;
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ReadonlyArray<RenameLocation> | undefined;
|
||||
getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
|
||||
getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined;
|
||||
getTypeDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /file1.ts
|
||||
////declare function log(s: string | number): void;
|
||||
////const [|{| "isWriteAccess": true, "isDefinition": true |}q|] = 1;
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}q|] };
|
||||
////const x = {
|
||||
//// [|{| "isWriteAccess": true, "isDefinition": true |}z|]: 'value'
|
||||
////}
|
||||
////const { [|{| "isWriteAccess": true, "isDefinition": true |}z|] } = x;
|
||||
////log([|z|]);
|
||||
|
||||
// @Filename: /file2.ts
|
||||
////declare function log(s: string | number): void;
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}q|] } from "./file1";
|
||||
////log([|q|] + 1);
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
const [q0, q1, z0, z1, z2, q2, q3] = test.ranges();
|
||||
const qFile1Ranges = [q0, q1];
|
||||
const qFile2Ranges = [q2, q3];
|
||||
const qFile1ReferenceGroup: FourSlashInterface.ReferenceGroup = {
|
||||
definition: "const q: 1",
|
||||
ranges: qFile1Ranges
|
||||
};
|
||||
const qFile2ReferenceGroup: FourSlashInterface.ReferenceGroup = {
|
||||
definition: "(alias) const q: 1\nimport q",
|
||||
ranges: qFile2Ranges
|
||||
};
|
||||
verify.referenceGroups([q0, q1], [qFile1ReferenceGroup, qFile2ReferenceGroup]);
|
||||
verify.referenceGroups([q2, q3], [qFile2ReferenceGroup, qFile1ReferenceGroup]);
|
||||
|
||||
verify.renameLocations(q0, { ranges: [q0, { range: q1, suffixText: " as q" }], providePrefixAndSuffixTextForRename: true });
|
||||
verify.renameLocations(q1, { ranges: [{ range: q1, prefixText: "q as " }, q2, q3], providePrefixAndSuffixTextForRename: true });
|
||||
verify.renameLocations([q2, q3], { ranges: [{ range: q2, prefixText: "q as " }, q3], providePrefixAndSuffixTextForRename: true });
|
||||
|
||||
verify.renameLocations([q0, q1, q2, q3], { ranges: [q0, q1, q2, q3], providePrefixAndSuffixTextForRename: false });
|
||||
|
||||
const zReferenceGroup1: FourSlashInterface.ReferenceGroup = {
|
||||
definition: "(property) z: string",
|
||||
ranges: [z0]
|
||||
};
|
||||
const zReferenceGroup2: FourSlashInterface.ReferenceGroup = {
|
||||
definition: "const z: string",
|
||||
ranges: [z1, z2]
|
||||
};
|
||||
|
||||
verify.referenceGroups([z0], [{ ...zReferenceGroup1, ranges: [z0, z1] }]);
|
||||
verify.referenceGroups([z1], [zReferenceGroup1, zReferenceGroup2]);
|
||||
verify.referenceGroups([z2], [zReferenceGroup2]);
|
||||
|
||||
verify.renameLocations([z0], { ranges: [z0, { range: z1, suffixText: ": z" }], providePrefixAndSuffixTextForRename: true });
|
||||
verify.renameLocations([z1, z2], { ranges: [{ range: z1, prefixText: "z: " }, z2], providePrefixAndSuffixTextForRename: true });
|
||||
|
||||
verify.renameLocations([z0, z1, z2], { ranges: [z0, z1, z2], providePrefixAndSuffixTextForRename: false });
|
||||
@@ -633,7 +633,8 @@ declare namespace FourSlashInterface {
|
||||
readonly findInStrings?: boolean;
|
||||
readonly findInComments?: boolean;
|
||||
readonly ranges: ReadonlyArray<RenameLocationOptions>;
|
||||
}
|
||||
readonly providePrefixAndSuffixTextForRename?: boolean;
|
||||
};
|
||||
type RenameLocationOptions = Range | { readonly range: Range, readonly prefixText?: string, readonly suffixText?: string };
|
||||
}
|
||||
declare function verifyOperationIsCancelled(f: any): void;
|
||||
|
||||
Reference in New Issue
Block a user