Add kindModifier to mark if a completion item is for an optional field (#20839)

* Add kindModifier to mark if a completion item is for an optional field

For #12458

Adds a new KindModifier for completion items to mark when a property is optional. This can be used by editors to either change the item icon or add a `?` to the item text

* Add method test

* Baseline-accept
This commit is contained in:
Matt Bierner 2018-01-04 16:36:31 -08:00 committed by Mohamed Hegazy
parent b36d614b56
commit 12d5063e4c
7 changed files with 38 additions and 8 deletions

View file

@ -872,7 +872,7 @@ namespace FourSlash {
});
}
public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string, spanIndex?: number, hasAction?: boolean, options?: FourSlashInterface.VerifyCompletionListContainsOptions) {
public verifyCompletionListContains(entryId: ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string | { kind?: string, kindModifiers?: 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, options);
@ -893,7 +893,7 @@ namespace FourSlash {
* @param expectedKind the kind of symbol (see ScriptElementKind)
* @param spanIndex the index of the range that the completion item's replacement text span should match
*/
public verifyCompletionListDoesNotContain(entryId: ts.Completions.CompletionEntryIdentifier, expectedText?: string, expectedDocumentation?: string, expectedKind?: string, spanIndex?: number, options?: FourSlashInterface.CompletionsAtOptions) {
public verifyCompletionListDoesNotContain(entryId: ts.Completions.CompletionEntryIdentifier, expectedText?: string, expectedDocumentation?: string, expectedKind?: string | { kind?: string, kindModifiers?: string }, spanIndex?: number, options?: FourSlashInterface.CompletionsAtOptions) {
let replacementSpan: ts.TextSpan;
if (spanIndex !== undefined) {
replacementSpan = this.getTextSpanForRangeAtIndex(spanIndex);
@ -902,7 +902,7 @@ namespace FourSlash {
const completions = this.getCompletionListAtCaret(options);
if (completions) {
let filterCompletions = completions.entries.filter(e => e.name === entryId.name && e.source === entryId.source);
filterCompletions = expectedKind ? filterCompletions.filter(e => e.kind === expectedKind) : filterCompletions;
filterCompletions = expectedKind ? filterCompletions.filter(e => e.kind === expectedKind || (typeof expectedKind === "object" && e.kind === expectedKind.kind)) : filterCompletions;
filterCompletions = filterCompletions.filter(entry => {
const details = this.getCompletionEntryDetails(entry.name);
const documentation = details && ts.displayPartsToString(details.documentation);
@ -3089,7 +3089,7 @@ Actual: ${stringify(fullActual)}`);
entryId: ts.Completions.CompletionEntryIdentifier,
text: string | undefined,
documentation: string | undefined,
kind: string | undefined,
kind: string | undefined | { kind?: string, kindModifiers?: string },
spanIndex: number | undefined,
hasAction: boolean | undefined,
options: FourSlashInterface.VerifyCompletionListContainsOptions | undefined,
@ -3123,9 +3123,21 @@ Actual: ${stringify(fullActual)}`);
}
if (kind !== undefined) {
assert.equal(item.kind, kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + entryId));
if (typeof kind === "string") {
assert.equal(item.kind, kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + entryId));
}
else {
if (kind.kind) {
assert.equal(item.kind, kind.kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + entryId));
}
if (kind.kindModifiers !== undefined) {
assert.equal(item.kindModifiers, kind.kindModifiers, this.assertionMessageAtLastKnownMarker("completion item kindModifiers for " + entryId));
}
}
}
if (spanIndex !== undefined) {
const span = this.getTextSpanForRangeAtIndex(spanIndex);
assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + entryId));
@ -3842,7 +3854,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?: VerifyCompletionListContainsOptions) {
public completionListContains(entryId: string | ts.Completions.CompletionEntryIdentifier, text?: string, documentation?: string, kind?: string | { kind?: string, kindModifiers?: string }, spanIndex?: number, hasAction?: boolean, options?: VerifyCompletionListContainsOptions) {
if (typeof entryId === "string") {
entryId = { name: entryId, source: undefined };
}

View file

@ -91,9 +91,14 @@ namespace ts.SymbolDisplay {
}
export function getSymbolModifiers(symbol: Symbol): string {
return symbol && symbol.declarations && symbol.declarations.length > 0
const nodeModifiers = symbol && symbol.declarations && symbol.declarations.length > 0
? getNodeModifiers(symbol.declarations[0])
: ScriptElementKindModifier.none;
const symbolModifiers = symbol && symbol.flags & SymbolFlags.Optional ?
ScriptElementKindModifier.optionalModifier
: ScriptElementKindModifier.none;
return nodeModifiers && symbolModifiers ? nodeModifiers + "," + symbolModifiers : nodeModifiers || symbolModifiers;
}
interface SymbolDisplayPartsDocumentationAndSymbolKind {

View file

@ -954,6 +954,7 @@ namespace ts {
ambientModifier = "declare",
staticModifier = "static",
abstractModifier = "abstract",
optionalModifier = "optional"
}
export const enum ClassificationTypeNames {

View file

@ -4505,6 +4505,7 @@ declare namespace ts {
ambientModifier = "declare",
staticModifier = "static",
abstractModifier = "abstract",
optionalModifier = "optional",
}
enum ClassificationTypeNames {
comment = "comment",

View file

@ -4505,6 +4505,7 @@ declare namespace ts {
ambientModifier = "declare",
staticModifier = "static",
abstractModifier = "abstract",
optionalModifier = "optional",
}
enum ClassificationTypeNames {
comment = "comment",

View file

@ -0,0 +1,10 @@
/// <reference path="fourslash.ts" />
////interface A { a?: number; method?(): number; };
////function f(x: A) {
////x./*a*/;
////}
goTo.marker("a");
verify.completionListContains("a", /* text */ undefined, /* documentation */ undefined, { kindModifiers: "optional" });
verify.completionListContains("method", /* text */ undefined, /* documentation */ undefined, { kindModifiers: "optional" });

View file

@ -146,7 +146,7 @@ declare namespace FourSlashInterface {
entryId: string | { name: string, source?: string },
text?: string,
documentation?: string,
kind?: string,
kind?: string | { kind?: string, kindModifiers?: string },
spanIndex?: number,
hasAction?: boolean,
options?: { includeExternalModuleExports?: boolean, sourceDisplay?: string, isRecommended?: true },