mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Merge pull request #32266 from fuafa/properties-priorities
Add properties priority for completion
This commit is contained in:
commit
c26c44d5fc
@ -2,10 +2,12 @@
|
||||
namespace ts.Completions {
|
||||
export enum SortText {
|
||||
LocationPriority = "0",
|
||||
SuggestedClassMembers = "1",
|
||||
GlobalsOrKeywords = "2",
|
||||
AutoImportSuggestions = "3",
|
||||
JavascriptIdentifiers = "4"
|
||||
OptionalMember = "1",
|
||||
MemberDeclaredBySpreadAssignment = "2",
|
||||
SuggestedClassMembers = "3",
|
||||
GlobalsOrKeywords = "4",
|
||||
AutoImportSuggestions = "5",
|
||||
JavascriptIdentifiers = "6"
|
||||
}
|
||||
export type Log = (message: string) => void;
|
||||
|
||||
@ -1109,6 +1111,7 @@ namespace ts.Completions {
|
||||
const attrsType = jsxContainer && typeChecker.getContextualType(jsxContainer.attributes);
|
||||
if (!attrsType) return GlobalsSearch.Continue;
|
||||
symbols = filterJsxAttributes(getPropertiesForObjectExpression(attrsType, jsxContainer!.attributes, typeChecker), jsxContainer!.attributes.properties);
|
||||
setSortTextToOptionalMember();
|
||||
completionKind = CompletionKind.MemberLike;
|
||||
isNewIdentifierLocation = false;
|
||||
return GlobalsSearch.Success;
|
||||
@ -1539,6 +1542,8 @@ namespace ts.Completions {
|
||||
// Add filtered items to the completion list
|
||||
symbols = filterObjectMembersList(typeMembers, Debug.assertDefined(existingMembers));
|
||||
}
|
||||
setSortTextToOptionalMember();
|
||||
|
||||
return GlobalsSearch.Success;
|
||||
}
|
||||
|
||||
@ -1910,6 +1915,7 @@ namespace ts.Completions {
|
||||
return contextualMemberSymbols;
|
||||
}
|
||||
|
||||
const membersDeclaredBySpreadAssignment = createMap<true>();
|
||||
const existingMemberNames = createUnderscoreEscapedMap<boolean>();
|
||||
for (const m of existingMembers) {
|
||||
// Ignore omitted expressions for missing members
|
||||
@ -1918,7 +1924,8 @@ namespace ts.Completions {
|
||||
m.kind !== SyntaxKind.BindingElement &&
|
||||
m.kind !== SyntaxKind.MethodDeclaration &&
|
||||
m.kind !== SyntaxKind.GetAccessor &&
|
||||
m.kind !== SyntaxKind.SetAccessor) {
|
||||
m.kind !== SyntaxKind.SetAccessor &&
|
||||
m.kind !== SyntaxKind.SpreadAssignment) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1929,7 +1936,10 @@ namespace ts.Completions {
|
||||
|
||||
let existingName: __String | undefined;
|
||||
|
||||
if (isBindingElement(m) && m.propertyName) {
|
||||
if (isSpreadAssignment(m)) {
|
||||
setMembersDeclaredBySpreadAssignment(m, membersDeclaredBySpreadAssignment);
|
||||
}
|
||||
else if (isBindingElement(m) && m.propertyName) {
|
||||
// include only identifiers in completion list
|
||||
if (m.propertyName.kind === SyntaxKind.Identifier) {
|
||||
existingName = m.propertyName.escapedText;
|
||||
@ -1946,7 +1956,43 @@ namespace ts.Completions {
|
||||
existingMemberNames.set(existingName!, true); // TODO: GH#18217
|
||||
}
|
||||
|
||||
return contextualMemberSymbols.filter(m => !existingMemberNames.get(m.escapedName));
|
||||
const filteredSymbols = contextualMemberSymbols.filter(m => !existingMemberNames.get(m.escapedName));
|
||||
setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment, filteredSymbols);
|
||||
|
||||
return filteredSymbols;
|
||||
}
|
||||
|
||||
function setMembersDeclaredBySpreadAssignment(declaration: SpreadAssignment | JsxSpreadAttribute, membersDeclaredBySpreadAssignment: Map<true>) {
|
||||
const expression = declaration.expression;
|
||||
const symbol = typeChecker.getSymbolAtLocation(expression);
|
||||
const type = symbol && typeChecker.getTypeOfSymbolAtLocation(symbol, expression);
|
||||
const properties = type && (<ObjectType>type).properties;
|
||||
if (properties) {
|
||||
properties.forEach(property => {
|
||||
membersDeclaredBySpreadAssignment.set(property.name, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Set SortText to OptionalMember if it is an optinoal member
|
||||
function setSortTextToOptionalMember() {
|
||||
symbols.forEach(m => {
|
||||
if (m.flags & SymbolFlags.Optional) {
|
||||
symbolToSortTextMap[getSymbolId(m)] = symbolToSortTextMap[getSymbolId(m)] || SortText.OptionalMember;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Set SortText to MemberDeclaredBySpreadAssignment if it is fulfilled by spread assignment
|
||||
function setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment: Map<true>, contextualMemberSymbols: Symbol[]): void {
|
||||
if (membersDeclaredBySpreadAssignment.size === 0) {
|
||||
return;
|
||||
}
|
||||
for (const contextualMemberSymbol of contextualMemberSymbols) {
|
||||
if (membersDeclaredBySpreadAssignment.has(contextualMemberSymbol.name)) {
|
||||
symbolToSortTextMap[getSymbolId(contextualMemberSymbol)] = SortText.MemberDeclaredBySpreadAssignment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2000,6 +2046,7 @@ namespace ts.Completions {
|
||||
*/
|
||||
function filterJsxAttributes(symbols: Symbol[], attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>): Symbol[] {
|
||||
const seenNames = createUnderscoreEscapedMap<boolean>();
|
||||
const membersDeclaredBySpreadAssignment = createMap<true>();
|
||||
for (const attr of attributes) {
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
if (isCurrentlyEditingNode(attr)) {
|
||||
@ -2009,9 +2056,15 @@ namespace ts.Completions {
|
||||
if (attr.kind === SyntaxKind.JsxAttribute) {
|
||||
seenNames.set(attr.name.escapedText, true);
|
||||
}
|
||||
else if (isJsxSpreadAttribute(attr)) {
|
||||
setMembersDeclaredBySpreadAssignment(attr, membersDeclaredBySpreadAssignment);
|
||||
}
|
||||
}
|
||||
const filteredSymbols = symbols.filter(a => !seenNames.get(a.escapedName));
|
||||
|
||||
return symbols.filter(a => !seenNames.get(a.escapedName));
|
||||
setSortTextToMemberDeclaredBySpreadAssignment(membersDeclaredBySpreadAssignment, filteredSymbols);
|
||||
|
||||
return filteredSymbols;
|
||||
}
|
||||
|
||||
function isCurrentlyEditingNode(node: Node): boolean {
|
||||
|
||||
@ -10,5 +10,5 @@
|
||||
|
||||
verify.completions({
|
||||
marker: "",
|
||||
exact: ["abc"],
|
||||
exact: [{ name: 'abc', kind: 'property', kindModifiers: 'declare,optional', sortText: completion.SortText.OptionalMember }],
|
||||
});
|
||||
|
||||
@ -5,4 +5,4 @@
|
||||
////declare const x: { m?(): void };
|
||||
////x./**/
|
||||
|
||||
verify.completions({ marker: "", exact: "m" });
|
||||
verify.completions({ marker: "", exact: "m" });
|
||||
31
tests/cases/fourslash/completionsPropertiesPriorities.ts
Normal file
31
tests/cases/fourslash/completionsPropertiesPriorities.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
// @strict: true
|
||||
|
||||
//// interface I {
|
||||
//// B?: number;
|
||||
//// a: number;
|
||||
//// c?: string;
|
||||
//// d: string
|
||||
//// }
|
||||
|
||||
//// const foo = {
|
||||
//// a: 1,
|
||||
//// B: 2
|
||||
//// }
|
||||
|
||||
//// const i: I = {
|
||||
//// ...foo,
|
||||
//// /*a*/
|
||||
//// }
|
||||
|
||||
verify.completions(
|
||||
{
|
||||
marker: ['a'],
|
||||
exact: [
|
||||
{ name: 'B', kindModifiers: 'optional', sortText: completion.SortText.MemberDeclaredBySpreadAssignment, kind: 'property' },
|
||||
{ name: 'a', sortText: completion.SortText.MemberDeclaredBySpreadAssignment, kind: 'property' },
|
||||
{ name: 'c', kindModifiers: 'optional', sortText: completion.SortText.OptionalMember, kind: 'property' },
|
||||
{ name: 'd', sortText: completion.SortText.LocationPriority, kind: 'property' }
|
||||
]
|
||||
}
|
||||
);
|
||||
@ -13,6 +13,8 @@
|
||||
|
||||
verify.completions({
|
||||
marker: "",
|
||||
includes: ['world']
|
||||
exact: [
|
||||
{ name: "world", kind: "property", kindModifiers: "optional", sortText: completion.SortText.OptionalMember }
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
@ -672,10 +672,12 @@ declare namespace completion {
|
||||
type Entry = FourSlashInterface.ExpectedCompletionEntryObject;
|
||||
export const enum SortText {
|
||||
LocationPriority = "0",
|
||||
SuggestedClassMembers = "1",
|
||||
GlobalsOrKeywords = "2",
|
||||
AutoImportSuggestions = "3",
|
||||
JavascriptIdentifiers = "4"
|
||||
OptionalMember = "1",
|
||||
MemberDeclaredBySpreadAssignment = "2",
|
||||
SuggestedClassMembers = "3",
|
||||
GlobalsOrKeywords = "4",
|
||||
AutoImportSuggestions = "5",
|
||||
JavascriptIdentifiers = "6"
|
||||
}
|
||||
export const globalThisEntry: Entry;
|
||||
export const undefinedVarEntry: Entry;
|
||||
|
||||
@ -23,7 +23,13 @@
|
||||
//// let opt4 = <Opt wrong /*5*/ />;
|
||||
|
||||
verify.completions(
|
||||
{ marker: ["1", "2", "5"], exact: ["propx", "propString", "optional"] },
|
||||
{ marker: "3", exact: ["propString", "optional"] },
|
||||
{
|
||||
marker: ["1", "2", "5"],
|
||||
exact: ["propx", "propString", { name: "optional", kind: "JSX attribute", kindModifiers: "optional", sortText: completion.SortText.OptionalMember }]
|
||||
},
|
||||
{
|
||||
marker: "3",
|
||||
exact: ["propString", { name: "optional", kind: "JSX attribute", kindModifiers: "optional", sortText: completion.SortText.OptionalMember }]
|
||||
},
|
||||
{ marker: "4", exact: "propString" },
|
||||
);
|
||||
|
||||
@ -31,7 +31,28 @@
|
||||
//// let opt = <MainButton wrong /*6*/ />;
|
||||
|
||||
verify.completions(
|
||||
{ marker: ["1", "6"], exact: ["onClick", "children", "className", "goTo"] },
|
||||
{ marker: "2", exact: ["onClick", "className", "goTo"] },
|
||||
{ marker: ["3", "4", "5"], exact: ["children", "className"] },
|
||||
{
|
||||
marker: ["1", "6"],
|
||||
exact: [
|
||||
"onClick",
|
||||
{ name: "children", kind: "JSX attribute", kindModifiers: "optional", sortText: completion.SortText.OptionalMember },
|
||||
{ name: "className", kind: "JSX attribute", kindModifiers: "optional", sortText: completion.SortText.OptionalMember },
|
||||
"goTo"
|
||||
]
|
||||
},
|
||||
{
|
||||
marker: "2",
|
||||
exact: [
|
||||
"onClick",
|
||||
{ name: "className", kind: "JSX attribute", kindModifiers: "optional", sortText: completion.SortText.OptionalMember },
|
||||
"goTo"
|
||||
]
|
||||
},
|
||||
{
|
||||
marker: ["3", "4", "5"],
|
||||
exact: [
|
||||
{ name: "children", kind: "JSX attribute", kindModifiers: "optional", sortText: completion.SortText.OptionalMember },
|
||||
{ name: "className", kind: "JSX attribute", kindModifiers: "optional", sortText: completion.SortText.OptionalMember }
|
||||
]
|
||||
},
|
||||
);
|
||||
|
||||
@ -10,4 +10,10 @@
|
||||
//// let y = { ONE: '' };
|
||||
//// var x = <div {...y} /**/ />;
|
||||
|
||||
verify.completions({ marker: "", exact: ["ONE", "TWO"] });
|
||||
verify.completions({
|
||||
marker: "",
|
||||
exact: [
|
||||
{ name: "ONE", kind: "JSX attribute", kindModifiers: "declare", sortText: completion.SortText.MemberDeclaredBySpreadAssignment },
|
||||
{ name: "TWO", kind: "JSX attribute", kindModifiers: "declare", sortText: completion.SortText.LocationPriority }
|
||||
]
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user