fix(41259) : JS autocomplete doesn't work for object literal shorthands (#41539)

* fix: #41259

* fix: #41259

* fix: fourslash

* fix: remove nested if

* fix: change tc result for #41259

* fix: less restrictive shorthand completion rules

* fix: use typeMembers to find out whether properties are empty

* fix: typo

* fix: lint

* fix: exclude Object in completion

* fix: test

* fix: testcase tidy up

* fix: apply completions for unclosed literal and missing comma

* fix: ignore auto-imports

* fix: use exact to ensure the order of completions

* fix: use exact to ensure the order of completions

* fix: add new lines so it can easy to be distinguished
This commit is contained in:
orange4glace
2020-12-23 03:36:52 +09:00
committed by GitHub
parent 22f452c5cd
commit 1e4a5c9b37
10 changed files with 161 additions and 13 deletions

View File

@@ -1086,6 +1086,7 @@ namespace ts.Completions {
const semanticStart = timestamp();
let completionKind = CompletionKind.None;
let isNewIdentifierLocation = false;
let isNonContextualObjectLiteral = false;
let keywordFilters = KeywordCompletionFilters.None;
// This also gets mutated in nested-functions after the return
let symbols: Symbol[] = [];
@@ -1471,6 +1472,8 @@ namespace ts.Completions {
}
function shouldOfferImportCompletions(): boolean {
// If current completion is for non-contextual Object literal shortahands, ignore auto-import symbols
if (isNonContextualObjectLiteral) return false;
// If not already a module, must have modules enabled.
if (!preferences.includeCompletionsForModuleExports) return false;
// If already using ES6 modules, OK to continue using them.
@@ -1892,13 +1895,29 @@ namespace ts.Completions {
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
const instantiatedType = tryGetObjectLiteralContextualType(objectLikeContainer, typeChecker);
// Check completions for Object property value shorthand
if (instantiatedType === undefined) {
return GlobalsSearch.Fail;
if (objectLikeContainer.flags & NodeFlags.InWithStatement) {
return GlobalsSearch.Fail;
}
isNonContextualObjectLiteral = true;
return GlobalsSearch.Continue;
}
const completionsType = typeChecker.getContextualType(objectLikeContainer, ContextFlags.Completions);
isNewIdentifierLocation = hasIndexSignature(completionsType || instantiatedType);
const hasStringIndexType = (completionsType || instantiatedType).getStringIndexType();
const hasNumberIndextype = (completionsType || instantiatedType).getNumberIndexType();
isNewIdentifierLocation = !!hasStringIndexType || !!hasNumberIndextype;
typeMembers = getPropertiesForObjectExpression(instantiatedType, completionsType, objectLikeContainer, typeChecker);
existingMembers = objectLikeContainer.properties;
if (typeMembers.length === 0) {
// Edge case: If NumberIndexType exists
if (!hasNumberIndextype) {
isNonContextualObjectLiteral = true;
return GlobalsSearch.Continue;
}
}
}
else {
Debug.assert(objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern);
@@ -2313,6 +2332,7 @@ namespace ts.Completions {
}
return isDeclarationName(contextToken)
&& !isShorthandPropertyAssignment(contextToken.parent)
&& !isJsxAttribute(contextToken.parent)
// Don't block completions if we're in `class C /**/`, because we're *past* the end of the identifier and might want to complete `extends`.
// If `contextToken !== previousToken`, this is `class C ex/**/`.