Skip to content

Commit 592ee00

Browse files
author
Andy
authored
Have CompletionEntryDetails source use a relative path (microsoft#19917)
* Have CompletionEntryDetails source use a relative path * Use getCanonicalFileName from services Instead of creating a new one
1 parent 9c51a85 commit 592ee00

24 files changed

+97
-49
lines changed

src/compiler/builder.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ namespace ts {
7777
}
7878

7979
export interface BuilderOptions {
80-
getCanonicalFileName: (fileName: string) => string;
80+
getCanonicalFileName: GetCanonicalFileName;
8181
computeHash: (data: string) => string;
8282
}
8383

src/compiler/commandLineParser.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1540,7 +1540,7 @@ namespace ts {
15401540
host: ParseConfigHost,
15411541
basePath: string,
15421542
configFileName: string,
1543-
getCanonicalFileName: (fileName: string) => string,
1543+
getCanonicalFileName: GetCanonicalFileName,
15441544
resolutionStack: Path[],
15451545
errors: Push<Diagnostic>,
15461546
): ParsedTsconfig {
@@ -1588,7 +1588,7 @@ namespace ts {
15881588
json: any,
15891589
host: ParseConfigHost,
15901590
basePath: string,
1591-
getCanonicalFileName: (fileName: string) => string,
1591+
getCanonicalFileName: GetCanonicalFileName,
15921592
configFileName: string | undefined,
15931593
errors: Push<Diagnostic>
15941594
): ParsedTsconfig {
@@ -1619,7 +1619,7 @@ namespace ts {
16191619
sourceFile: JsonSourceFile,
16201620
host: ParseConfigHost,
16211621
basePath: string,
1622-
getCanonicalFileName: (fileName: string) => string,
1622+
getCanonicalFileName: GetCanonicalFileName,
16231623
configFileName: string | undefined,
16241624
errors: Push<Diagnostic>
16251625
): ParsedTsconfig {
@@ -1688,7 +1688,7 @@ namespace ts {
16881688
extendedConfig: string,
16891689
host: ParseConfigHost,
16901690
basePath: string,
1691-
getCanonicalFileName: (fileName: string) => string,
1691+
getCanonicalFileName: GetCanonicalFileName,
16921692
errors: Push<Diagnostic>,
16931693
createDiagnostic: (message: DiagnosticMessage, arg1?: string) => Diagnostic) {
16941694
extendedConfig = normalizeSlashes(extendedConfig);
@@ -1713,7 +1713,7 @@ namespace ts {
17131713
extendedConfigPath: Path,
17141714
host: ts.ParseConfigHost,
17151715
basePath: string,
1716-
getCanonicalFileName: (fileName: string) => string,
1716+
getCanonicalFileName: GetCanonicalFileName,
17171717
resolutionStack: Path[],
17181718
errors: Push<Diagnostic>,
17191719
): ParsedTsconfig | undefined {

src/compiler/core.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -2033,7 +2033,7 @@ namespace ts {
20332033
}
20342034
}
20352035

2036-
export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: (fileName: string) => string, isAbsolutePathAnUrl: boolean) {
2036+
export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, isAbsolutePathAnUrl: boolean) {
20372037
const pathComponents = getNormalizedPathOrUrlComponents(relativeOrAbsolutePath, currentDirectory);
20382038
const directoryComponents = getNormalizedPathOrUrlComponents(directoryPathOrUrl, currentDirectory);
20392039
if (directoryComponents.length > 1 && lastOrUndefined(directoryComponents) === "") {
@@ -2819,7 +2819,8 @@ namespace ts {
28192819
}
28202820
}
28212821

2822-
export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): (fileName: string) => string {
2822+
export type GetCanonicalFileName = (fileName: string) => string;
2823+
export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): GetCanonicalFileName {
28232824
return useCaseSensitiveFileNames
28242825
? ((fileName) => fileName)
28252826
: ((fileName) => fileName.toLowerCase());

src/compiler/program.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace ts {
2020
}
2121

2222
/* @internal */
23-
export function computeCommonSourceDirectoryOfFilenames(fileNames: string[], currentDirectory: string, getCanonicalFileName: (fileName: string) => string): string {
23+
export function computeCommonSourceDirectoryOfFilenames(fileNames: string[], currentDirectory: string, getCanonicalFileName: GetCanonicalFileName): string {
2424
let commonPathComponents: string[];
2525
const failed = forEach(fileNames, sourceFile => {
2626
// Each file contributes into common source file path

src/harness/fourslash.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -867,10 +867,10 @@ namespace FourSlash {
867867
});
868868
}
869869

870-
public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: ts.GetCompletionsAtPositionOptions) {
870+
public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: FourSlashInterface.VerifyCompletionListContainsOptions) {
871871
const completions = this.getCompletionListAtCaret(options);
872872
if (completions) {
873-
this.assertItemInCompletionList(completions.entries, entryId, text, documentation, kind, spanIndex, hasAction);
873+
this.assertItemInCompletionList(completions.entries, entryId, text, documentation, kind, spanIndex, hasAction, options);
874874
}
875875
else {
876876
this.raiseError(`No completions at position '${this.currentCaretPosition}' when looking for '${JSON.stringify(entryId)}'.`);
@@ -3071,6 +3071,7 @@ Actual: ${stringify(fullActual)}`);
30713071
kind: string | undefined,
30723072
spanIndex: number | undefined,
30733073
hasAction: boolean | undefined,
3074+
options: FourSlashInterface.VerifyCompletionListContainsOptions | undefined,
30743075
) {
30753076
for (const item of items) {
30763077
if (item.name === entryId.name && item.source === entryId.source) {
@@ -3084,7 +3085,12 @@ Actual: ${stringify(fullActual)}`);
30843085
assert.equal(ts.displayPartsToString(details.displayParts), text, this.assertionMessageAtLastKnownMarker("completion item detail text for " + entryId));
30853086
}
30863087

3087-
assert.deepEqual(details.source, entryId.source === undefined ? undefined : [ts.textPart(entryId.source)]);
3088+
if (entryId.source === undefined) {
3089+
assert.equal(options && options.sourceDisplay, undefined);
3090+
}
3091+
else {
3092+
assert.deepEqual(details.source, [ts.textPart(options!.sourceDisplay)]);
3093+
}
30883094
}
30893095

30903096
if (kind !== undefined) {
@@ -3811,7 +3817,7 @@ namespace FourSlashInterface {
38113817

38123818
// Verifies the completion list contains the specified symbol. The
38133819
// completion list is brought up if necessary
3814-
public completionListContains(entryId: string | ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: ts.GetCompletionsAtPositionOptions) {
3820+
public completionListContains(entryId: string | ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: VerifyCompletionListContainsOptions) {
38153821
if (typeof entryId === "string") {
38163822
entryId = { name: entryId, source: undefined };
38173823
}
@@ -4547,6 +4553,10 @@ namespace FourSlashInterface {
45474553
isNewIdentifierLocation?: boolean;
45484554
}
45494555

4556+
export interface VerifyCompletionListContainsOptions extends ts.GetCompletionsAtPositionOptions {
4557+
sourceDisplay: string;
4558+
}
4559+
45504560
export interface NewContentOptions {
45514561
// Exactly one of these should be defined.
45524562
newFileContent?: string;

src/services/codefixes/importFixes.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ namespace ts.codefix {
3434
host: LanguageServiceHost;
3535
checker: TypeChecker;
3636
compilerOptions: CompilerOptions;
37-
getCanonicalFileName(fileName: string): string;
37+
getCanonicalFileName: GetCanonicalFileName;
3838
cachedImportDeclarations?: ImportDeclarationMap;
3939
}
4040

@@ -313,7 +313,7 @@ namespace ts.codefix {
313313
}
314314
}
315315

316-
function getModuleSpecifierForNewImport(sourceFile: SourceFile, moduleSymbol: Symbol, options: CompilerOptions, getCanonicalFileName: (file: string) => string, host: LanguageServiceHost): string | undefined {
316+
export function getModuleSpecifierForNewImport(sourceFile: SourceFile, moduleSymbol: Symbol, options: CompilerOptions, getCanonicalFileName: (file: string) => string, host: LanguageServiceHost): string | undefined {
317317
const moduleFileName = moduleSymbol.valueDeclaration.getSourceFile().fileName;
318318
const sourceDirectory = getDirectoryPath(sourceFile.fileName);
319319

@@ -523,7 +523,7 @@ namespace ts.codefix {
523523
return state > States.NodeModules ? { topLevelNodeModulesIndex, topLevelPackageNameIndex, packageRootIndex, fileNameIndex } : undefined;
524524
}
525525

526-
function getPathRelativeToRootDirs(path: string, rootDirs: ReadonlyArray<string>, getCanonicalFileName: (fileName: string) => string): string | undefined {
526+
function getPathRelativeToRootDirs(path: string, rootDirs: ReadonlyArray<string>, getCanonicalFileName: GetCanonicalFileName): string | undefined {
527527
return firstDefined(rootDirs, rootDir => getRelativePathIfInDirectory(path, rootDir, getCanonicalFileName));
528528
}
529529

@@ -535,12 +535,12 @@ namespace ts.codefix {
535535
return fileName;
536536
}
537537

538-
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: (fileName: string) => string): string | undefined {
538+
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined {
539539
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
540540
return isRootedDiskPath(relativePath) || startsWith(relativePath, "..") ? undefined : relativePath;
541541
}
542542

543-
function getRelativePath(path: string, directoryPath: string, getCanonicalFileName: (fileName: string) => string) {
543+
function getRelativePath(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName) {
544544
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
545545
return !pathIsRelative(relativePath) ? "./" + relativePath : relativePath;
546546
}

src/services/completions.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,9 @@ namespace ts.Completions {
422422
allSourceFiles: ReadonlyArray<SourceFile>,
423423
host: LanguageServiceHost,
424424
formatContext: formatting.FormatContext,
425+
getCanonicalFileName: GetCanonicalFileName,
425426
): CompletionEntryDetails {
426-
const { name, source } = entryId;
427+
const { name } = entryId;
427428
// Compute all the completion symbols again.
428429
const symbolCompletion = getSymbolCompletionFromEntryId(typeChecker, log, compilerOptions, sourceFile, position, entryId, allSourceFiles);
429430
switch (symbolCompletion.type) {
@@ -442,10 +443,10 @@ namespace ts.Completions {
442443
}
443444
case "symbol": {
444445
const { symbol, location, symbolToOriginInfoMap } = symbolCompletion;
445-
const codeActions = getCompletionEntryCodeActions(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, formatContext);
446+
const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, formatContext, getCanonicalFileName);
446447
const kindModifiers = SymbolDisplay.getSymbolModifiers(symbol);
447448
const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
448-
return { name, kindModifiers, kind: symbolKind, displayParts, documentation, tags, codeActions, source: source === undefined ? undefined : [textPart(source)] };
449+
return { name, kindModifiers, kind: symbolKind, displayParts, documentation, tags, codeActions, source: sourceDisplay };
449450
}
450451
case "none": {
451452
// Didn't find a symbol with this name. See if we can find a keyword instead.
@@ -466,33 +467,37 @@ namespace ts.Completions {
466467
}
467468
}
468469

469-
function getCompletionEntryCodeActions(
470+
function getCompletionEntryCodeActionsAndSourceDisplay(
470471
symbolToOriginInfoMap: SymbolOriginInfoMap,
471472
symbol: Symbol,
472473
checker: TypeChecker,
473474
host: LanguageServiceHost,
474475
compilerOptions: CompilerOptions,
475476
sourceFile: SourceFile,
476477
formatContext: formatting.FormatContext,
477-
): CodeAction[] | undefined {
478+
getCanonicalFileName: GetCanonicalFileName,
479+
): { codeActions: CodeAction[] | undefined, sourceDisplay: SymbolDisplayPart[] | undefined } {
478480
const symbolOriginInfo = symbolToOriginInfoMap[getSymbolId(symbol)];
479481
if (!symbolOriginInfo) {
480-
return undefined;
482+
return { codeActions: undefined, sourceDisplay: undefined };
481483
}
482484

483485
const { moduleSymbol, isDefaultExport } = symbolOriginInfo;
484-
return codefix.getCodeActionForImport(moduleSymbol, {
486+
487+
const sourceDisplay = [textPart(codefix.getModuleSpecifierForNewImport(sourceFile, moduleSymbol, compilerOptions, getCanonicalFileName, host))];
488+
const codeActions = codefix.getCodeActionForImport(moduleSymbol, {
485489
host,
486490
checker,
487491
newLineCharacter: host.getNewLine(),
488492
compilerOptions,
489493
sourceFile,
490494
formatContext,
491495
symbolName: getSymbolName(symbol, symbolOriginInfo, compilerOptions.target),
492-
getCanonicalFileName: createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : false),
496+
getCanonicalFileName,
493497
symbolToken: undefined,
494498
kind: isDefaultExport ? codefix.ImportKind.Default : codefix.ImportKind.Named,
495499
});
500+
return { sourceDisplay, codeActions };
496501
}
497502

498503
export function getCompletionEntrySymbol(

src/services/rename.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* @internal */
22
namespace ts.Rename {
3-
export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: (fileName: string) => string, sourceFile: SourceFile, position: number): RenameInfo {
3+
export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: GetCanonicalFileName, sourceFile: SourceFile, position: number): RenameInfo {
44
const getCanonicalDefaultLibName = memoize(() => getCanonicalFileName(ts.normalizePath(defaultLibFileName)));
55
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
66
const renameInfo = node && nodeIsEligibleForRename(node)

src/services/services.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ namespace ts {
938938
private _compilationSettings: CompilerOptions;
939939
private currentDirectory: string;
940940

941-
constructor(private host: LanguageServiceHost, getCanonicalFileName: (fileName: string) => string) {
941+
constructor(private host: LanguageServiceHost, getCanonicalFileName: GetCanonicalFileName) {
942942
// script id => script index
943943
this.currentDirectory = host.getCurrentDirectory();
944944
this.fileNameToEntry = createMap<CachedHostFileInformation>();
@@ -1447,7 +1447,8 @@ namespace ts {
14471447
{ name, source },
14481448
program.getSourceFiles(),
14491449
host,
1450-
formattingOptions && formatting.getFormatContext(formattingOptions));
1450+
formattingOptions && formatting.getFormatContext(formattingOptions),
1451+
getCanonicalFileName);
14511452
}
14521453

14531454
function getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string): Symbol {

tests/cases/fourslash/completionsImport_default_addToNamedImports.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
////f/**/;
1010

1111
goTo.marker("");
12-
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
12+
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, {
13+
includeExternalModuleExports: true,
14+
sourceDisplay: "./a",
15+
});
1316

1417
verify.applyCodeActionFromCompletion("", {
1518
name: "foo",

tests/cases/fourslash/completionsImport_default_addToNamespaceImport.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
////f/**/;
99

1010
goTo.marker("");
11-
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
11+
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, {
12+
includeExternalModuleExports: true,
13+
sourceDisplay: "./a",
14+
});
1215

1316
verify.applyCodeActionFromCompletion("", {
1417
name: "foo",

tests/cases/fourslash/completionsImport_default_alreadyExistedWithRename.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
////f/**/;
99

1010
goTo.marker("");
11-
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
11+
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, {
12+
includeExternalModuleExports: true,
13+
sourceDisplay: "./a",
14+
});
1215

1316
verify.applyCodeActionFromCompletion("", {
1417
name: "foo",

tests/cases/fourslash/completionsImport_default_anonymous.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010
////fooB/*1*/
1111

1212
goTo.marker("0");
13-
verify.not.completionListContains({ name: "default", source: "/src/foo-bar" }, undefined, undefined, undefined, undefined, undefined, { includeExternalModuleExports: true });
13+
const options = {
14+
includeExternalModuleExports: true,
15+
sourceDisplay: "./foo-bar",
16+
};
17+
verify.not.completionListContains({ name: "default", source: "/src/foo-bar" }, undefined, undefined, undefined, undefined, undefined, options);
1418

1519
goTo.marker("1");
16-
verify.completionListContains({ name: "fooBar", source: "/src/foo-bar" }, "(property) default: 0", "", "property", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
20+
verify.completionListContains({ name: "fooBar", source: "/src/foo-bar" }, "(property) default: 0", "", "property", /*spanIndex*/ undefined, /*hasAction*/ true, options);
1721
verify.applyCodeActionFromCompletion("1", {
1822
name: "fooBar",
1923
source: "/src/foo-bar",

tests/cases/fourslash/completionsImport_default_didNotExistBefore.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
////f/**/;
88

99
goTo.marker("");
10-
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
10+
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, {
11+
includeExternalModuleExports: true,
12+
sourceDisplay: "./a",
13+
});
1114

1215
verify.applyCodeActionFromCompletion("", {
1316
name: "foo",

tests/cases/fourslash/completionsImport_matching.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
goTo.marker("");
1616

17-
const options = { includeExternalModuleExports: true };
17+
const options = { includeExternalModuleExports: true, sourceDisplay: "./a" };
1818
verify.not.completionListContains({ name: "abcde", source: "/a" }, undefined, undefined, undefined, undefined, undefined, options);
1919
verify.not.completionListContains({ name: "dbf", source: "/a" }, undefined, undefined, undefined, undefined, undefined, options);
2020

0 commit comments

Comments
 (0)