Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ namespace ts {
}

export interface BuilderOptions {
getCanonicalFileName: (fileName: string) => string;
getCanonicalFileName: GetCanonicalFileName;
computeHash: (data: string) => string;
}

Expand Down
10 changes: 5 additions & 5 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,7 @@ namespace ts {
host: ParseConfigHost,
basePath: string,
configFileName: string,
getCanonicalFileName: (fileName: string) => string,
getCanonicalFileName: GetCanonicalFileName,
resolutionStack: Path[],
errors: Push<Diagnostic>,
): ParsedTsconfig {
Expand Down Expand Up @@ -1588,7 +1588,7 @@ namespace ts {
json: any,
host: ParseConfigHost,
basePath: string,
getCanonicalFileName: (fileName: string) => string,
getCanonicalFileName: GetCanonicalFileName,
configFileName: string | undefined,
errors: Push<Diagnostic>
): ParsedTsconfig {
Expand Down Expand Up @@ -1619,7 +1619,7 @@ namespace ts {
sourceFile: JsonSourceFile,
host: ParseConfigHost,
basePath: string,
getCanonicalFileName: (fileName: string) => string,
getCanonicalFileName: GetCanonicalFileName,
configFileName: string | undefined,
errors: Push<Diagnostic>
): ParsedTsconfig {
Expand Down Expand Up @@ -1688,7 +1688,7 @@ namespace ts {
extendedConfig: string,
host: ParseConfigHost,
basePath: string,
getCanonicalFileName: (fileName: string) => string,
getCanonicalFileName: GetCanonicalFileName,
errors: Push<Diagnostic>,
createDiagnostic: (message: DiagnosticMessage, arg1?: string) => Diagnostic) {
extendedConfig = normalizeSlashes(extendedConfig);
Expand All @@ -1713,7 +1713,7 @@ namespace ts {
extendedConfigPath: Path,
host: ts.ParseConfigHost,
basePath: string,
getCanonicalFileName: (fileName: string) => string,
getCanonicalFileName: GetCanonicalFileName,
resolutionStack: Path[],
errors: Push<Diagnostic>,
): ParsedTsconfig | undefined {
Expand Down
5 changes: 3 additions & 2 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2033,7 +2033,7 @@ namespace ts {
}
}

export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: (fileName: string) => string, isAbsolutePathAnUrl: boolean) {
export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: GetCanonicalFileName, isAbsolutePathAnUrl: boolean) {
const pathComponents = getNormalizedPathOrUrlComponents(relativeOrAbsolutePath, currentDirectory);
const directoryComponents = getNormalizedPathOrUrlComponents(directoryPathOrUrl, currentDirectory);
if (directoryComponents.length > 1 && lastOrUndefined(directoryComponents) === "") {
Expand Down Expand Up @@ -2808,7 +2808,8 @@ namespace ts {
}
}

export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): (fileName: string) => string {
export type GetCanonicalFileName = (fileName: string) => string;
export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): GetCanonicalFileName {
return useCaseSensitiveFileNames
? ((fileName) => fileName)
: ((fileName) => fileName.toLowerCase());
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace ts {
}

/* @internal */
export function computeCommonSourceDirectoryOfFilenames(fileNames: string[], currentDirectory: string, getCanonicalFileName: (fileName: string) => string): string {
export function computeCommonSourceDirectoryOfFilenames(fileNames: string[], currentDirectory: string, getCanonicalFileName: GetCanonicalFileName): string {
let commonPathComponents: string[];
const failed = forEach(fileNames, sourceFile => {
// Each file contributes into common source file path
Expand Down
18 changes: 14 additions & 4 deletions src/harness/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -867,10 +867,10 @@ namespace FourSlash {
});
}

public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: ts.GetCompletionsAtPositionOptions) {
public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: FourSlashInterface.VerifyCompletionListContainsOptions) {
const completions = this.getCompletionListAtCaret(options);
if (completions) {
this.assertItemInCompletionList(completions.entries, entryId, text, documentation, kind, spanIndex, hasAction);
this.assertItemInCompletionList(completions.entries, entryId, text, documentation, kind, spanIndex, hasAction, options);
}
else {
this.raiseError(`No completions at position '${this.currentCaretPosition}' when looking for '${JSON.stringify(entryId)}'.`);
Expand Down Expand Up @@ -3071,6 +3071,7 @@ Actual: ${stringify(fullActual)}`);
kind: string | undefined,
spanIndex: number | undefined,
hasAction: boolean | undefined,
options: FourSlashInterface.VerifyCompletionListContainsOptions | undefined,
) {
for (const item of items) {
if (item.name === entryId.name && item.source === entryId.source) {
Expand All @@ -3084,7 +3085,12 @@ Actual: ${stringify(fullActual)}`);
assert.equal(ts.displayPartsToString(details.displayParts), text, this.assertionMessageAtLastKnownMarker("completion item detail text for " + entryId));
}

assert.deepEqual(details.source, entryId.source === undefined ? undefined : [ts.textPart(entryId.source)]);
if (entryId.source === undefined) {
assert.equal(options && options.sourceDisplay, undefined);
}
else {
assert.deepEqual(details.source, [ts.textPart(options!.sourceDisplay)]);
}
}

if (kind !== undefined) {
Expand Down Expand Up @@ -3811,7 +3817,7 @@ namespace FourSlashInterface {

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

export interface VerifyCompletionListContainsOptions extends ts.GetCompletionsAtPositionOptions {
sourceDisplay: string;
}

export interface NewContentOptions {
// Exactly one of these should be defined.
newFileContent?: string;
Expand Down
10 changes: 5 additions & 5 deletions src/services/codefixes/importFixes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace ts.codefix {
host: LanguageServiceHost;
checker: TypeChecker;
compilerOptions: CompilerOptions;
getCanonicalFileName(fileName: string): string;
getCanonicalFileName: GetCanonicalFileName;
cachedImportDeclarations?: ImportDeclarationMap;
}

Expand Down Expand Up @@ -313,7 +313,7 @@ namespace ts.codefix {
}
}

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

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

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

Expand All @@ -535,12 +535,12 @@ namespace ts.codefix {
return fileName;
}

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

function getRelativePath(path: string, directoryPath: string, getCanonicalFileName: (fileName: string) => string) {
function getRelativePath(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName) {
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
return !pathIsRelative(relativePath) ? "./" + relativePath : relativePath;
}
Expand Down
21 changes: 13 additions & 8 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,9 @@ namespace ts.Completions {
allSourceFiles: ReadonlyArray<SourceFile>,
host: LanguageServiceHost,
formatContext: formatting.FormatContext,
getCanonicalFileName: GetCanonicalFileName,
): CompletionEntryDetails {
const { name, source } = entryId;
const { name } = entryId;
// Compute all the completion symbols again.
const symbolCompletion = getSymbolCompletionFromEntryId(typeChecker, log, compilerOptions, sourceFile, position, entryId, allSourceFiles);
switch (symbolCompletion.type) {
Expand All @@ -442,10 +443,10 @@ namespace ts.Completions {
}
case "symbol": {
const { symbol, location, symbolToOriginInfoMap } = symbolCompletion;
const codeActions = getCompletionEntryCodeActions(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, formatContext);
const { codeActions, sourceDisplay } = getCompletionEntryCodeActionsAndSourceDisplay(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, formatContext, getCanonicalFileName);
const kindModifiers = SymbolDisplay.getSymbolModifiers(symbol);
const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
return { name, kindModifiers, kind: symbolKind, displayParts, documentation, tags, codeActions, source: source === undefined ? undefined : [textPart(source)] };
return { name, kindModifiers, kind: symbolKind, displayParts, documentation, tags, codeActions, source: sourceDisplay };
}
case "none": {
// Didn't find a symbol with this name. See if we can find a keyword instead.
Expand All @@ -466,33 +467,37 @@ namespace ts.Completions {
}
}

function getCompletionEntryCodeActions(
function getCompletionEntryCodeActionsAndSourceDisplay(
symbolToOriginInfoMap: SymbolOriginInfoMap,
symbol: Symbol,
checker: TypeChecker,
host: LanguageServiceHost,
compilerOptions: CompilerOptions,
sourceFile: SourceFile,
formatContext: formatting.FormatContext,
): CodeAction[] | undefined {
getCanonicalFileName: GetCanonicalFileName,
): { codeActions: CodeAction[] | undefined, sourceDisplay: SymbolDisplayPart[] | undefined } {
const symbolOriginInfo = symbolToOriginInfoMap[getSymbolId(symbol)];
if (!symbolOriginInfo) {
return undefined;
return { codeActions: undefined, sourceDisplay: undefined };
}

const { moduleSymbol, isDefaultExport } = symbolOriginInfo;
return codefix.getCodeActionForImport(moduleSymbol, {

const sourceDisplay = [textPart(codefix.getModuleSpecifierForNewImport(sourceFile, moduleSymbol, compilerOptions, getCanonicalFileName, host))];
const codeActions = codefix.getCodeActionForImport(moduleSymbol, {
host,
checker,
newLineCharacter: host.getNewLine(),
compilerOptions,
sourceFile,
formatContext,
symbolName: getSymbolName(symbol, symbolOriginInfo, compilerOptions.target),
getCanonicalFileName: createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : false),
getCanonicalFileName,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to pass in the getCanonicalFileName instead of creating it all the time? services has already created one.

symbolToken: undefined,
kind: isDefaultExport ? codefix.ImportKind.Default : codefix.ImportKind.Named,
});
return { sourceDisplay, codeActions };
}

export function getCompletionEntrySymbol(
Expand Down
2 changes: 1 addition & 1 deletion src/services/rename.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* @internal */
namespace ts.Rename {
export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: (fileName: string) => string, sourceFile: SourceFile, position: number): RenameInfo {
export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: GetCanonicalFileName, sourceFile: SourceFile, position: number): RenameInfo {
const getCanonicalDefaultLibName = memoize(() => getCanonicalFileName(ts.normalizePath(defaultLibFileName)));
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
const renameInfo = node && nodeIsEligibleForRename(node)
Expand Down
5 changes: 3 additions & 2 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,7 @@ namespace ts {
private _compilationSettings: CompilerOptions;
private currentDirectory: string;

constructor(private host: LanguageServiceHost, getCanonicalFileName: (fileName: string) => string) {
constructor(private host: LanguageServiceHost, getCanonicalFileName: GetCanonicalFileName) {
// script id => script index
this.currentDirectory = host.getCurrentDirectory();
this.fileNameToEntry = createMap<CachedHostFileInformation>();
Expand Down Expand Up @@ -1429,7 +1429,8 @@ namespace ts {
{ name, source },
program.getSourceFiles(),
host,
formattingOptions && formatting.getFormatContext(formattingOptions));
formattingOptions && formatting.getFormatContext(formattingOptions),
getCanonicalFileName);
}

function getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string): Symbol {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
////f/**/;

goTo.marker("");
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, {
includeExternalModuleExports: true,
sourceDisplay: "./a",
});

verify.applyCodeActionFromCompletion("", {
name: "foo",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
////f/**/;

goTo.marker("");
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, {
includeExternalModuleExports: true,
sourceDisplay: "./a",
});

verify.applyCodeActionFromCompletion("", {
name: "foo",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
////f/**/;

goTo.marker("");
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, {
includeExternalModuleExports: true,
sourceDisplay: "./a",
});

verify.applyCodeActionFromCompletion("", {
name: "foo",
Expand Down
8 changes: 6 additions & 2 deletions tests/cases/fourslash/completionsImport_default_anonymous.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@
////fooB/*1*/

goTo.marker("0");
verify.not.completionListContains({ name: "default", source: "/src/foo-bar" }, undefined, undefined, undefined, undefined, undefined, { includeExternalModuleExports: true });
const options = {
includeExternalModuleExports: true,
sourceDisplay: "./foo-bar",
};
verify.not.completionListContains({ name: "default", source: "/src/foo-bar" }, undefined, undefined, undefined, undefined, undefined, options);

goTo.marker("1");
verify.completionListContains({ name: "fooBar", source: "/src/foo-bar" }, "(property) default: 0", "", "property", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
verify.completionListContains({ name: "fooBar", source: "/src/foo-bar" }, "(property) default: 0", "", "property", /*spanIndex*/ undefined, /*hasAction*/ true, options);
verify.applyCodeActionFromCompletion("1", {
name: "fooBar",
source: "/src/foo-bar",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
////f/**/;

goTo.marker("");
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, { includeExternalModuleExports: true });
verify.completionListContains({ name: "foo", source: "/a" }, "function foo(): void", "", "function", /*spanIndex*/ undefined, /*hasAction*/ true, {
includeExternalModuleExports: true,
sourceDisplay: "./a",
});

verify.applyCodeActionFromCompletion("", {
name: "foo",
Expand Down
2 changes: 1 addition & 1 deletion tests/cases/fourslash/completionsImport_matching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

goTo.marker("");

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

Expand Down
Loading