mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-11 06:02:53 -05:00
Simplify tryGetImportOrExportClauseCompletionSymbols (#22961)
* Simplify tryGetImportOrExportClauseCompletionSymbols * Handle undefined key in arrayToSet
This commit is contained in:
@@ -1314,12 +1314,13 @@ namespace ts {
|
||||
* the same key with the given 'makeKey' function, then the element with the higher
|
||||
* index in the array will be the one associated with the produced key.
|
||||
*/
|
||||
export function arrayToMap<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string): Map<T>;
|
||||
export function arrayToMap<T, U>(array: ReadonlyArray<T>, makeKey: (value: T) => string, makeValue: (value: T) => U): Map<U>;
|
||||
export function arrayToMap<T, U>(array: ReadonlyArray<T>, makeKey: (value: T) => string, makeValue: (value: T) => T | U = identity): Map<T | U> {
|
||||
export function arrayToMap<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string | undefined): Map<T>;
|
||||
export function arrayToMap<T, U>(array: ReadonlyArray<T>, makeKey: (value: T) => string | undefined, makeValue: (value: T) => U): Map<U>;
|
||||
export function arrayToMap<T, U>(array: ReadonlyArray<T>, makeKey: (value: T) => string | undefined, makeValue: (value: T) => T | U = identity): Map<T | U> {
|
||||
const result = createMap<T | U>();
|
||||
for (const value of array) {
|
||||
result.set(makeKey(value), makeValue(value));
|
||||
const key = makeKey(value);
|
||||
if (key !== undefined) result.set(key, makeValue(value));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1340,8 +1341,9 @@ namespace ts {
|
||||
* @param array the array of input elements.
|
||||
*/
|
||||
export function arrayToSet(array: ReadonlyArray<string>): Map<true>;
|
||||
export function arrayToSet<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string): Map<true>;
|
||||
export function arrayToSet(array: ReadonlyArray<any>, makeKey?: (value: any) => string): Map<true> {
|
||||
export function arrayToSet<T>(array: ReadonlyArray<T>, makeKey: (value: T) => string | undefined): Map<true>;
|
||||
export function arrayToSet<T>(array: ReadonlyArray<T>, makeKey: (value: T) => __String | undefined): UnderscoreEscapedMap<true>;
|
||||
export function arrayToSet(array: ReadonlyArray<any>, makeKey?: (value: any) => string | __String | undefined): Map<true> | UnderscoreEscapedMap<true> {
|
||||
return arrayToMap<any, true>(array, makeKey || (s => s), () => true);
|
||||
}
|
||||
|
||||
|
||||
@@ -6325,4 +6325,9 @@ namespace ts {
|
||||
export function isStringLiteralLike(node: Node): node is StringLiteralLike {
|
||||
return node.kind === SyntaxKind.StringLiteral || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function isNamedImportsOrExports(node: Node): node is NamedImportsOrExports {
|
||||
return node.kind === SyntaxKind.NamedImports || node.kind === SyntaxKind.NamedExports;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1555,32 +1555,22 @@ namespace ts.Completions {
|
||||
* @returns true if 'symbols' was successfully populated; false otherwise.
|
||||
*/
|
||||
function tryGetImportOrExportClauseCompletionSymbols(): GlobalsSearch {
|
||||
const namedImportsOrExports = tryGetNamedImportsOrExportsForCompletion(contextToken);
|
||||
if (!namedImportsOrExports) return undefined;
|
||||
// `import { |` or `import { a as 0, | }`
|
||||
const namedImportsOrExports = contextToken && (contextToken.kind === SyntaxKind.OpenBraceToken || contextToken.kind === SyntaxKind.CommaToken)
|
||||
? tryCast(contextToken.parent, isNamedImportsOrExports) : undefined;
|
||||
if (!namedImportsOrExports) return GlobalsSearch.Continue;
|
||||
|
||||
// cursor is in an import clause
|
||||
// try to show exported member for imported module
|
||||
const declarationKind = namedImportsOrExports.kind === SyntaxKind.NamedImports ?
|
||||
SyntaxKind.ImportDeclaration :
|
||||
SyntaxKind.ExportDeclaration;
|
||||
const importOrExportDeclaration = <ImportDeclaration | ExportDeclaration>getAncestor(namedImportsOrExports, declarationKind);
|
||||
const moduleSpecifier = importOrExportDeclaration.moduleSpecifier;
|
||||
|
||||
if (!moduleSpecifier) {
|
||||
return GlobalsSearch.Fail;
|
||||
}
|
||||
const { moduleSpecifier } = namedImportsOrExports.kind === SyntaxKind.NamedImports ? namedImportsOrExports.parent.parent : namedImportsOrExports.parent;
|
||||
const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(moduleSpecifier);
|
||||
if (!moduleSpecifierSymbol) return GlobalsSearch.Fail;
|
||||
|
||||
completionKind = CompletionKind.MemberLike;
|
||||
isNewIdentifierLocation = false;
|
||||
|
||||
const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(moduleSpecifier);
|
||||
if (!moduleSpecifierSymbol) {
|
||||
symbols = emptyArray;
|
||||
return GlobalsSearch.Fail;
|
||||
}
|
||||
|
||||
const exports = typeChecker.getExportsAndPropertiesOfModule(moduleSpecifierSymbol);
|
||||
symbols = filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements);
|
||||
const existing = arrayToSet<ImportOrExportSpecifier>(namedImportsOrExports.elements, n => isCurrentlyEditingNode(n) ? undefined : (n.propertyName || n.name).escapedText);
|
||||
symbols = exports.filter(e => e.escapedName !== InternalSymbolName.Default && !existing.get(e.escapedName));
|
||||
return GlobalsSearch.Success;
|
||||
}
|
||||
|
||||
@@ -1648,26 +1638,6 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the containing list of named imports or exports of a context token,
|
||||
* on the condition that one exists and that the context implies completion should be given.
|
||||
*/
|
||||
function tryGetNamedImportsOrExportsForCompletion(contextToken: Node): NamedImportsOrExports {
|
||||
if (contextToken) {
|
||||
switch (contextToken.kind) {
|
||||
case SyntaxKind.OpenBraceToken: // import { |
|
||||
case SyntaxKind.CommaToken: // import { a as 0, |
|
||||
switch (contextToken.parent.kind) {
|
||||
case SyntaxKind.NamedImports:
|
||||
case SyntaxKind.NamedExports:
|
||||
return <NamedImportsOrExports>contextToken.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function isConstructorParameterCompletion(node: Node): boolean {
|
||||
return !!node.parent && isParameter(node.parent) && isConstructorDeclaration(node.parent.parent)
|
||||
&& (isParameterPropertyModifier(node.kind) || isDeclarationName(node));
|
||||
@@ -1911,31 +1881,6 @@ namespace ts.Completions {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out completion suggestions for named imports or exports.
|
||||
*
|
||||
* @param exportsOfModule The list of symbols which a module exposes.
|
||||
* @param namedImportsOrExports The list of existing import/export specifiers in the import/export clause.
|
||||
*
|
||||
* @returns Symbols to be suggested at an import/export clause, barring those whose named imports/exports
|
||||
* do not occur at the current position and have not otherwise been typed.
|
||||
*/
|
||||
function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ReadonlyArray<ImportOrExportSpecifier>): Symbol[] {
|
||||
const existingImportsOrExports = createUnderscoreEscapedMap<boolean>();
|
||||
|
||||
for (const element of namedImportsOrExports) {
|
||||
// If this is the current item we are editing right now, do not filter it out
|
||||
if (isCurrentlyEditingNode(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const name = element.propertyName || element.name;
|
||||
existingImportsOrExports.set(name.escapedText, true);
|
||||
}
|
||||
|
||||
return exportsOfModule.filter(e => e.escapedName !== InternalSymbolName.Default && !existingImportsOrExports.get(e.escapedName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out completion suggestions for named imports or exports.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user