Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f6c3566
fix services' type's isLiteral
gabritto Sep 23, 2022
4467330
update literal completions tests
gabritto Sep 23, 2022
a206fe1
initial prototype
gabritto Sep 7, 2022
73c1eea
use symbol to expression. TODO: filter existing, replace import nodes
gabritto Sep 16, 2022
5648cba
WIP
gabritto Sep 23, 2022
d46c0d2
WIP
gabritto Sep 28, 2022
297f892
remove booleans from literals
gabritto Sep 28, 2022
fd1d6ed
Merge branch 'gabritto/servicesIsLiteral' into gabritto/switchsnippet
gabritto Sep 28, 2022
4c528b3
trigger at case keyword positions
gabritto Sep 29, 2022
1a5cd05
clean up tests
gabritto Nov 8, 2022
ee42732
fix element access expression case
gabritto Nov 9, 2022
1819d0b
refactor dealing with existing values into a tracker
gabritto Nov 9, 2022
b19543e
Merge branch 'main' into gabritto/switchsnippet
gabritto Nov 10, 2022
bd5b817
fix merge errors
gabritto Nov 10, 2022
f02122b
cleanup and more tests
gabritto Nov 10, 2022
a35bc4a
fix lint errors
gabritto Nov 10, 2022
83b88f7
more merge conflict fixes and cleanup
gabritto Nov 11, 2022
599fb30
use appropriate quotes
gabritto Nov 11, 2022
97dcf69
small indentation fix
gabritto Nov 11, 2022
3b92638
refactor case clause tracker
gabritto Nov 14, 2022
89f6f6b
Merge branch 'main' into gabritto/switchsnippet
gabritto Nov 14, 2022
1894d2e
experiment: support tabstops after each case clause
gabritto Nov 22, 2022
90767fc
address small CR comments
gabritto Nov 23, 2022
d1c8968
fix completion entry details; add test case
gabritto Nov 30, 2022
fb15ba1
Merge branch 'main' into gabritto/switchsnippet
gabritto Nov 30, 2022
3980b93
fix lint errors
gabritto Dec 1, 2022
8823108
remove space before tab stops; refactor
gabritto Dec 1, 2022
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
Prev Previous commit
Next Next commit
fix element access expression case
  • Loading branch information
gabritto committed Nov 9, 2022
commit ee42732e6ddf6ae454dfe66f51fe13142b0fda13
60 changes: 35 additions & 25 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -600,17 +600,10 @@ namespace ts.Completions {
formatContext: formatting.FormatContext | undefined): { entry: CompletionEntry, importAdder: codefix.ImportAdder } | undefined {

const clauses = caseBlock.clauses;
// >> TODO: Only offer this completion if we're not positioned *after* a default clause
// const defaultClauseIndex = findIndex(clauses, isDefaultClause);
// const currentIndex = findIndex(clauses, c => c === caseClause);
// if (defaultClauseIndex !== -1 && currentIndex > defaultClauseIndex) {
// return undefined;
// }
const checker = program.getTypeChecker();
// const switchType = getSwitchedType(caseClause, checker);
const switchType = checker.getTypeAtLocation(caseBlock.parent.expression);
// >> TODO: handle unit type case?
if (switchType && switchType.isUnion() && every(switchType.types, type => type.isLiteral())) {// >> TODO: does this work for enum members? aliases?
if (switchType && switchType.isUnion() && every(switchType.types, type => type.isLiteral())) {
const existingStrings = new Set<string>();
const existingNumbers = new Set<number>();
const existingBigInts = new Set<string>();
Expand Down Expand Up @@ -685,7 +678,7 @@ namespace ts.Completions {
if (!typeNode) {
return undefined;
}
const expr = foo(typeNode, target);
const expr = typeNodeToExpression(typeNode, target);
if (!expr) {
return undefined;
}
Expand Down Expand Up @@ -742,9 +735,8 @@ namespace ts.Completions {
return {
entry: {
name: `${firstClause} ...`, // >> TODO: what should this be?
// isRecommended: true, // >> I assume that is ok because if there's another recommended, it will be sorted after this one
kind: ScriptElementKind.unknown, // >> TODO: what should this be?
sortText: SortText.GlobalsOrKeywords, // >> TODO: sort *right after* case keyword
sortText: SortText.GlobalsOrKeywords,
insertText,
hasAction: importAdder.hasFixes() || undefined,
source: CompletionSource.SwitchCases,
Expand All @@ -756,30 +748,48 @@ namespace ts.Completions {
return undefined;
}

function foo(typeNode: TypeNode, languageVersion: ScriptTarget): Expression | undefined {
function typeNodeToExpression(typeNode: TypeNode, languageVersion: ScriptTarget): Expression | undefined {
switch (typeNode.kind) {
case SyntaxKind.TypeReference:
const typeName = (typeNode as TypeReferenceNode).typeName;
return bar(typeName);
return entityNameToExpression(typeName, languageVersion);
case SyntaxKind.ImportType:
Debug.fail(`We should not get an import type after calling 'codefix.typeToAutoImportableTypeNode'.`);
case SyntaxKind.IndexedAccessType:
return undefined; // >> TODO: do we need this case?
const objectExpression = typeNodeToExpression((typeNode as IndexedAccessTypeNode).objectType, languageVersion);
const indexExpression = typeNodeToExpression((typeNode as IndexedAccessTypeNode).indexType, languageVersion);
return objectExpression
&& indexExpression
&& factory.createElementAccessExpression(objectExpression, indexExpression);
case SyntaxKind.LiteralType:
const literal = (typeNode as LiteralTypeNode).literal;
switch (literal.kind) {
case SyntaxKind.StringLiteral:
return factory.createStringLiteral(literal.text); // >> TODO: where to get 'issinglequote' from?
case SyntaxKind.NumericLiteral:
return factory.createNumericLiteral(literal.text, (literal as NumericLiteral).numericLiteralFlags);
}
return undefined;
case SyntaxKind.ParenthesizedType:
const exp = typeNodeToExpression((typeNode as ParenthesizedTypeNode).type, languageVersion);
return exp && (isIdentifier(exp) ? exp : factory.createParenthesizedExpression(exp));
case SyntaxKind.TypeQuery:
return entityNameToExpression((typeNode as TypeQueryNode).exprName, languageVersion);
}

return undefined;
}

function bar(entityName: EntityName): Expression {
if (isIdentifier(entityName)) {
return entityName;
}
const realName = unescapeLeadingUnderscores(entityName.right.escapedText);
if (canUsePropertyAccess(realName, languageVersion)) {
return factory.createPropertyAccessExpression(bar(entityName.left), realName);
}
else {
return factory.createElementAccessExpression(bar(entityName.left), factory.createStringLiteral(`"${realName}"`)); // >> TODO: this is wrong
}
function entityNameToExpression(entityName: EntityName, languageVersion: ScriptTarget): Expression {
if (isIdentifier(entityName)) {
return entityName;
}
const realName = unescapeLeadingUnderscores(entityName.right.escapedText);
if (canUsePropertyAccess(realName, languageVersion)) {
return factory.createPropertyAccessExpression(entityNameToExpression(entityName.left, languageVersion), realName);
}
else {
return factory.createElementAccessExpression(entityNameToExpression(entityName.left, languageVersion), factory.createStringLiteral(`"${realName}"`)); // >> TODO: this is wrong
}
}

Expand Down
35 changes: 35 additions & 0 deletions tests/cases/fourslash/fullCaseCompletions5.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// <reference path="fourslash.ts" />

// Filter existing values.

// @newline: LF
//// enum P {
//// " Space",
//// Bar,
//// }
////
//// declare const p: P;
////
//// switch (p) {
//// /*1*/
//// }

verify.completions(
{
marker: "1",
isNewIdentifierLocation: false,
includes: [
{
name: `case P[" Space"]: ...`,
source: completion.CompletionSource.SwitchCases,
sortText: completion.SortText.GlobalsOrKeywords,
insertText:
`case P[" Space"]:
case P.Bar:`,
},
],
preferences: {
includeCompletionsWithInsertText: true,
},
},
);