Skip to content

Commit 080ba6f

Browse files
committed
Allow nodebuilder to use import types where appropriate
1 parent 9e77045 commit 080ba6f

File tree

2 files changed

+44
-13
lines changed

2 files changed

+44
-13
lines changed

src/compiler/checker.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2953,7 +2953,7 @@ namespace ts {
29532953
if (type.flags & TypeFlags.UniqueESSymbol) {
29542954
if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) {
29552955
if (isValueSymbolAccessible(type.symbol, context.enclosingDeclaration)) {
2956-
return createTypeQueryNode(symbolToName(type.symbol, context, SymbolFlags.Value, /*expectsIdentifier*/ false));
2956+
return symbolToTypeNode(type.symbol, context, SymbolFlags.Value);
29572957
}
29582958
if (context.tracker.reportInaccessibleUniqueSymbolError) {
29592959
context.tracker.reportInaccessibleUniqueSymbolError();
@@ -3072,15 +3072,14 @@ namespace ts {
30723072
if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) && !(symbol.valueDeclaration.kind === SyntaxKind.ClassExpression && context.flags & NodeBuilderFlags.WriteClassExpressionAsTypeLiteral) ||
30733073
symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) ||
30743074
shouldWriteTypeOfFunctionSymbol()) {
3075-
return createTypeQueryNodeFromSymbol(symbol, SymbolFlags.Value);
3075+
return symbolToTypeNode(symbol, context, SymbolFlags.Value);
30763076
}
30773077
else if (contains(context.symbolStack, symbol)) {
30783078
// If type is an anonymous type literal in a type alias declaration, use type alias name
30793079
const typeAlias = getTypeAliasForTypeLiteral(type);
30803080
if (typeAlias) {
30813081
// The specified symbol flags need to be reinterpreted as type flags
3082-
const entityName = symbolToName(typeAlias, context, SymbolFlags.Type, /*expectsIdentifier*/ false);
3083-
return createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
3082+
return symbolToTypeNode(typeAlias, context, SymbolFlags.Type);
30843083
}
30853084
else {
30863085
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
@@ -3158,11 +3157,6 @@ namespace ts {
31583157
return setEmitFlags(typeLiteralNode, (context.flags & NodeBuilderFlags.MultilineObjectLiterals) ? 0 : EmitFlags.SingleLine);
31593158
}
31603159

3161-
function createTypeQueryNodeFromSymbol(symbol: Symbol, symbolFlags: SymbolFlags) {
3162-
const entityName = symbolToName(symbol, context, symbolFlags, /*expectsIdentifier*/ false);
3163-
return createTypeQueryNode(entityName);
3164-
}
3165-
31663160
function symbolToTypeReferenceName(symbol: Symbol) {
31673161
// Unnamed function expressions and arrow functions have reserved names that we don't want to display
31683162
const entityName = symbol.flags & SymbolFlags.Class || !isReservedMemberName(symbol.escapedName) ? symbolToName(symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ false) : createIdentifier("");
@@ -3559,6 +3553,41 @@ namespace ts {
35593553
return typeParameterNodes;
35603554
}
35613555

3556+
function symbolToTypeNode(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags): TypeQueryNode | TypeReferenceNode | ImportTypeNode {
3557+
const chain = lookupSymbolChain(symbol, context, meaning);
3558+
3559+
context.flags |= NodeBuilderFlags.InInitialEntityName;
3560+
const rootName = getNameOfSymbolAsWritten(chain[0], context);
3561+
context.flags ^= NodeBuilderFlags.InInitialEntityName;
3562+
3563+
const isTypeOf = meaning === SymbolFlags.Value;
3564+
if (ambientModuleSymbolRegex.test(rootName)) {
3565+
// module is root, must use `ImportTypeNode`
3566+
const nonRootParts = chain.length > 1 ? createEntityNameFromSymbolChain(chain, chain.length - 1, 1) : undefined;
3567+
return createImportTypeNode(createLiteralTypeNode(createLiteral(rootName.substring(1, rootName.length - 1))), nonRootParts, isTypeOf);
3568+
}
3569+
3570+
const entityName = createEntityNameFromSymbolChain(chain, chain.length - 1, 0);
3571+
return isTypeOf ? createTypeQueryNode(entityName) : createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
3572+
3573+
function createEntityNameFromSymbolChain(chain: Symbol[], index: number, stopper: number): EntityName {
3574+
const typeParameterNodes = lookupTypeParameterNodes(chain, index, context);
3575+
const symbol = chain[index];
3576+
3577+
if (index === 0) {
3578+
context.flags |= NodeBuilderFlags.InInitialEntityName;
3579+
}
3580+
const symbolName = getNameOfSymbolAsWritten(symbol, context);
3581+
if (index === 0) {
3582+
context.flags ^= NodeBuilderFlags.InInitialEntityName;
3583+
}
3584+
const identifier = setEmitFlags(createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping);
3585+
identifier.symbol = symbol;
3586+
3587+
return index > stopper ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1, stopper), identifier) : identifier;
3588+
}
3589+
}
3590+
35623591
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: true): Identifier;
35633592
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: false): EntityName;
35643593
function symbolToName(symbol: Symbol, context: NodeBuilderContext, meaning: SymbolFlags, expectsIdentifier: boolean): EntityName {

src/compiler/factory.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -802,17 +802,19 @@ namespace ts {
802802
: node;
803803
}
804804

805-
export function createImportTypeNode(argument: TypeNode, qualifier?: EntityName) {
805+
export function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, isTypeOf?: boolean) {
806806
const node = <ImportTypeNode>createSynthesizedNode(SyntaxKind.ImportTypeNode);
807807
node.argument = argument;
808808
node.qualifier = qualifier;
809+
node.isTypeOf = isTypeOf;
809810
return node;
810811
}
811812

812-
export function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName) {
813+
export function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName, isTypeOf?: boolean) {
813814
return node.argument !== argument
814-
&& node.qualifier !== qualifier
815-
? updateNode(createImportTypeNode(argument, qualifier), node)
815+
|| node.qualifier !== qualifier
816+
|| !!node.isTypeOf !== !!isTypeOf
817+
? updateNode(createImportTypeNode(argument, qualifier, isTypeOf), node)
816818
: node;
817819
}
818820

0 commit comments

Comments
 (0)