Add option to configure automatic optional chain completions (#34552)

Add option to configure automatic optional chain completions
This commit is contained in:
Daniel Rosenwasser
2019-10-18 17:35:59 -07:00
committed by GitHub
7 changed files with 60 additions and 5 deletions
+1
View File
@@ -6452,6 +6452,7 @@ namespace ts {
readonly disableSuggestions?: boolean;
readonly quotePreference?: "auto" | "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeAutomaticOptionalChainCompletions?: boolean;
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
+6
View File
@@ -3007,6 +3007,12 @@ namespace ts.server.protocol {
* For those entries, The `insertText` and `replacementSpan` properties will be set to change from `.x` property access to `["x"]`.
*/
readonly includeCompletionsWithInsertText?: boolean;
/**
* Unless this option is `false`, or `includeCompletionsWithInsertText` is not enabled,
* member completion lists triggered with `.` will include entries on potentially-null and potentially-undefined
* values, with insertion text to replace preceding `.` tokens with `?.`.
*/
readonly includeAutomaticOptionalChainCompletions?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
+24 -5
View File
@@ -338,6 +338,7 @@ namespace ts.Completions {
): CompletionEntry | undefined {
let insertText: string | undefined;
let replacementSpan: TextSpan | undefined;
const insertQuestionDot = origin && originIsNullableMember(origin);
const useBraces = origin && originIsSymbolMember(origin) || needsConvertPropertyAccess;
if (origin && originIsThisType(origin)) {
@@ -780,7 +781,7 @@ namespace ts.Completions {
sourceFile: SourceFile,
isUncheckedFile: boolean,
position: number,
preferences: Pick<UserPreferences, "includeCompletionsForModuleExports" | "includeCompletionsWithInsertText">,
preferences: Pick<UserPreferences, "includeCompletionsForModuleExports" | "includeCompletionsWithInsertText" | "includeAutomaticOptionalChainCompletions">,
detailsEntryId: CompletionEntryIdentifier | undefined,
host: LanguageServiceHost,
): CompletionData | Request | undefined {
@@ -1116,8 +1117,17 @@ namespace ts.Completions {
let type = typeChecker.getTypeOfSymbolAtLocation(symbol, node).getNonOptionalType();
let insertQuestionDot = false;
if (type.isNullableType()) {
insertQuestionDot = isRightOfDot && !isRightOfQuestionDot;
type = type.getNonNullableType();
const canCorrectToQuestionDot =
isRightOfDot &&
!isRightOfQuestionDot &&
preferences.includeAutomaticOptionalChainCompletions !== false;
if (canCorrectToQuestionDot || isRightOfQuestionDot) {
type = type.getNonNullableType();
if (canCorrectToQuestionDot) {
insertQuestionDot = true;
}
}
}
addTypeProperties(type, !!(node.flags & NodeFlags.AwaitContext), insertQuestionDot);
}
@@ -1137,8 +1147,17 @@ namespace ts.Completions {
let type = typeChecker.getTypeAtLocation(node).getNonOptionalType();
let insertQuestionDot = false;
if (type.isNullableType()) {
insertQuestionDot = isRightOfDot && !isRightOfQuestionDot;
type = type.getNonNullableType();
const canCorrectToQuestionDot =
isRightOfDot &&
!isRightOfQuestionDot &&
preferences.includeAutomaticOptionalChainCompletions !== false;
if (canCorrectToQuestionDot || isRightOfQuestionDot) {
type = type.getNonNullableType();
if (canCorrectToQuestionDot) {
insertQuestionDot = true;
}
}
}
addTypeProperties(type, !!(node.flags & NodeFlags.AwaitContext), insertQuestionDot);
}
+7
View File
@@ -3171,6 +3171,7 @@ declare namespace ts {
readonly disableSuggestions?: boolean;
readonly quotePreference?: "auto" | "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeAutomaticOptionalChainCompletions?: boolean;
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
@@ -8295,6 +8296,12 @@ declare namespace ts.server.protocol {
* For those entries, The `insertText` and `replacementSpan` properties will be set to change from `.x` property access to `["x"]`.
*/
readonly includeCompletionsWithInsertText?: boolean;
/**
* Unless this option is `false`, or `includeCompletionsWithInsertText` is not enabled,
* member completion lists triggered with `.` will include entries on potentially-null and potentially-undefined
* values, with insertion text to replace preceding `.` tokens with `?.`.
*/
readonly includeAutomaticOptionalChainCompletions?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
+1
View File
@@ -3171,6 +3171,7 @@ declare namespace ts {
readonly disableSuggestions?: boolean;
readonly quotePreference?: "auto" | "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeAutomaticOptionalChainCompletions?: boolean;
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
@@ -0,0 +1,20 @@
/// <reference path="fourslash.ts" />
// @strict: true
//// interface User {
//// address?: {
//// city: string;
//// "postal code": string;
//// }
//// };
//// declare const user: User;
//// user.address[|./**/|]
verify.completions({
marker: "",
exact: [],
preferences: {
includeInsertTextCompletions: true,
includeAutomaticOptionalChainCompletions: false
},
});
+1
View File
@@ -583,6 +583,7 @@ declare namespace FourSlashInterface {
readonly quotePreference?: "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeInsertTextCompletions?: boolean;
readonly includeAutomaticOptionalChainCompletions?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
}