diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 26299645537e6..dd963952e0bda 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5490,16 +5490,20 @@ namespace ts { qualifier = factory.updateIdentifier(qualifier, typeArguments); } else { - qualifier = factory.updateQualifiedName(qualifier, - qualifier.left, - factory.updateIdentifier(qualifier.right, typeArguments)); + if (isIdentifier(qualifier.right)) { + qualifier = factory.updateQualifiedName(qualifier, + qualifier.left, + factory.updateIdentifier(qualifier.right, typeArguments)); + } } } typeArguments = ref.typeArguments; // then move qualifiers const ids = getAccessStack(ref); for (const id of ids) { - qualifier = qualifier ? factory.createQualifiedName(qualifier, id) : id; + if (isIdentifier(id)) { + qualifier = qualifier ? factory.createQualifiedName(qualifier, id) : id; + } } return factory.updateImportTypeNode( root, @@ -5516,9 +5520,11 @@ namespace ts { typeName = factory.updateIdentifier(typeName, typeArguments); } else { - typeName = factory.updateQualifiedName(typeName, - typeName.left, - factory.updateIdentifier(typeName.right, typeArguments)); + if (isIdentifier(typeName.right)) { + typeName = factory.updateQualifiedName(typeName, + typeName.left, + factory.updateIdentifier(typeName.right, typeArguments)); + } } typeArguments = ref.typeArguments; // then move qualifiers @@ -5533,7 +5539,7 @@ namespace ts { } } - function getAccessStack(ref: TypeReferenceNode): Identifier[] { + function getAccessStack(ref: TypeReferenceNode): MemberName[] { let state = ref.typeName; const ids = []; while (!isIdentifier(state)) { @@ -5920,12 +5926,7 @@ namespace ts { const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && parameterDeclaration.modifiers ? parameterDeclaration.modifiers.map(factory.cloneNode) : undefined; const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; const dotDotDotToken = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined; - const name = parameterDeclaration ? parameterDeclaration.name ? - parameterDeclaration.name.kind === SyntaxKind.Identifier ? setEmitFlags(factory.cloneNode(parameterDeclaration.name), EmitFlags.NoAsciiEscaping) : - parameterDeclaration.name.kind === SyntaxKind.QualifiedName ? setEmitFlags(factory.cloneNode(parameterDeclaration.name.right), EmitFlags.NoAsciiEscaping) : - cloneBindingName(parameterDeclaration.name) : - symbolName(parameterSymbol) : - symbolName(parameterSymbol); + const name = createParameterName(parameterSymbol, parameterDeclaration); const isOptional = parameterDeclaration && isOptionalParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.OptionalParameter; const questionToken = isOptional ? factory.createToken(SyntaxKind.QuestionToken) : undefined; const parameterNode = factory.createParameterDeclaration( @@ -5939,6 +5940,19 @@ namespace ts { context.approximateLength += symbolName(parameterSymbol).length + 3; return parameterNode; + function createParameterName(symbol: Symbol, declaration: ParameterDeclaration | JSDocParameterTag | undefined): string | BindingName { + if (declaration && declaration.name) { + if (isIdentifier(declaration.name)) { + return setEmitFlags(factory.cloneNode(declaration.name), EmitFlags.NoAsciiEscaping); + } + if (isQualifiedName(declaration.name)) { + return isIdentifier(declaration.name.right) ? setEmitFlags(factory.cloneNode(declaration.name.right), EmitFlags.NoAsciiEscaping) : symbolName(symbol); + } + return cloneBindingName(declaration.name); + } + return symbolName(symbol); + } + function cloneBindingName(node: BindingName): BindingName { return elideInitializerAndSetEmitFlags(node) as BindingName; function elideInitializerAndSetEmitFlags(node: Node): Node { @@ -6241,7 +6255,9 @@ namespace ts { if (!nonRootParts || isEntityName(nonRootParts)) { if (nonRootParts) { const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right; - lastId.typeArguments = undefined; + if (isIdentifier(lastId)) { + lastId.typeArguments = undefined; + } } return factory.createImportTypeNode(lit, assertion, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf); } @@ -6261,9 +6277,12 @@ namespace ts { } else { const lastId = isIdentifier(entityName) ? entityName : entityName.right; - const lastTypeArgs = lastId.typeArguments; - lastId.typeArguments = undefined; - return factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray); + let lastTypeArgs; + if (isIdentifier(lastId)) { + lastTypeArgs = lastId.typeArguments as NodeArray; + lastId.typeArguments = undefined; + } + return factory.createTypeReferenceNode(entityName, lastTypeArgs); } function createAccessFromSymbolChain(chain: Symbol[], index: number, stopper: number): EntityName | IndexedAccessTypeNode { @@ -16152,7 +16171,7 @@ namespace ts { return links.resolvedType; } - function getIdentifierChain(node: EntityName): Identifier[] { + function getIdentifierChain(node: EntityName): MemberName[] { if (isIdentifier(node)) { return [node]; } @@ -16183,9 +16202,9 @@ namespace ts { } const moduleSymbol = resolveExternalModuleSymbol(innerModuleSymbol, /*dontResolveAlias*/ false); if (!nodeIsMissing(node.qualifier)) { - const nameStack: Identifier[] = getIdentifierChain(node.qualifier!); + const nameStack: MemberName[] = getIdentifierChain(node.qualifier!); let currentNamespace = moduleSymbol; - let current: Identifier | undefined; + let current: MemberName | undefined; while (current = nameStack.shift()) { const meaning = nameStack.length ? SymbolFlags.Namespace : targetMeaning; // typeof a.b.c is normally resolved using `checkExpression` which in turn defers to `checkQualifiedName` @@ -29315,7 +29334,7 @@ namespace ts { return symbolResult && symbolName(symbolResult); } - function getSuggestedSymbolForNonexistentModule(name: Identifier, targetModule: Symbol): Symbol | undefined { + function getSuggestedSymbolForNonexistentModule(name: MemberName, targetModule: Symbol): Symbol | undefined { return targetModule.exports && getSpellingSuggestionForName(idText(name), getExportsOfModuleAsArray(targetModule), SymbolFlags.ModuleMember); } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index cbeb8df5e5b25..da3b121574546 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1093,13 +1093,12 @@ namespace ts { // // @api - function createQualifiedName(left: EntityName, right: string | Identifier) { + function createQualifiedName(left: EntityName, right: string | MemberName) { const node = createBaseNode(SyntaxKind.QualifiedName); node.left = left; node.right = asName(right); node.transformFlags |= - propagateChildFlags(node.left) | - propagateIdentifierNameFlags(node.right); + propagateChildFlags(node.left) | (isIdentifier(node.right) ? propagateIdentifierNameFlags(node.right) : propagateChildFlags(node.right)); return node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 7642612e27a44..0e514c63de32a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2843,7 +2843,7 @@ namespace ts { entity = finishNode( factory.createQualifiedName( entity, - parseRightSideOfDot(allowReservedWords, allowPrivateIdentifiers) as Identifier + parseRightSideOfDot(allowReservedWords, allowPrivateIdentifiers) ), pos ); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0831da97a629c..0abf6a34d845e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1166,7 +1166,7 @@ namespace ts { export interface QualifiedName extends Node { readonly kind: SyntaxKind.QualifiedName; readonly left: EntityName; - readonly right: Identifier; + readonly right: MemberName; /*@internal*/ jsdocDotPos?: number; // QualifiedName occurs in JSDoc-style generic: Id1.Id2. } @@ -4326,7 +4326,7 @@ namespace ts { /* @internal */ getSuggestionForNonexistentProperty(name: MemberName | string, containingType: Type): string | undefined; /* @internal */ getSuggestedSymbolForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined; /* @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined; - /* @internal */ getSuggestedSymbolForNonexistentModule(node: Identifier, target: Symbol): Symbol | undefined; + /* @internal */ getSuggestedSymbolForNonexistentModule(node: MemberName, target: Symbol): Symbol | undefined; /* @internal */ getSuggestedSymbolForNonexistentClassMember(name: string, baseType: Type): Symbol | undefined; /* @internal */ getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined; getBaseConstraintOfType(type: Type): Type | undefined; @@ -7257,8 +7257,8 @@ namespace ts { // Names // - createQualifiedName(left: EntityName, right: string | Identifier): QualifiedName; - updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier): QualifiedName; + createQualifiedName(left: EntityName, right: string | MemberName): QualifiedName; + updateQualifiedName(node: QualifiedName, left: EntityName, right: MemberName): QualifiedName; createComputedPropertyName(expression: Expression): ComputedPropertyName; updateComputedPropertyName(node: ComputedPropertyName, expression: Expression): ComputedPropertyName; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 6146af8bb9f75..882a5aee8dd2c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -659,7 +659,7 @@ declare namespace ts { export interface QualifiedName extends Node { readonly kind: SyntaxKind.QualifiedName; readonly left: EntityName; - readonly right: Identifier; + readonly right: MemberName; } export type EntityName = Identifier | QualifiedName; export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier; @@ -3395,8 +3395,8 @@ declare namespace ts { createFalse(): FalseLiteral; createModifier(kind: T): ModifierToken; createModifiersFromModifierFlags(flags: ModifierFlags): Modifier[] | undefined; - createQualifiedName(left: EntityName, right: string | Identifier): QualifiedName; - updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier): QualifiedName; + createQualifiedName(left: EntityName, right: string | MemberName): QualifiedName; + updateQualifiedName(node: QualifiedName, left: EntityName, right: MemberName): QualifiedName; createComputedPropertyName(expression: Expression): ComputedPropertyName; updateComputedPropertyName(node: ComputedPropertyName, expression: Expression): ComputedPropertyName; createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration; @@ -10803,9 +10803,9 @@ declare namespace ts { /** @deprecated Use `factory.createModifiersFromModifierFlags` or the factory supplied by your transformation context instead. */ const createModifiersFromModifierFlags: (flags: ModifierFlags) => Modifier[] | undefined; /** @deprecated Use `factory.createQualifiedName` or the factory supplied by your transformation context instead. */ - const createQualifiedName: (left: EntityName, right: string | Identifier) => QualifiedName; + const createQualifiedName: (left: EntityName, right: string | MemberName) => QualifiedName; /** @deprecated Use `factory.updateQualifiedName` or the factory supplied by your transformation context instead. */ - const updateQualifiedName: (node: QualifiedName, left: EntityName, right: Identifier) => QualifiedName; + const updateQualifiedName: (node: QualifiedName, left: EntityName, right: MemberName) => QualifiedName; /** @deprecated Use `factory.createComputedPropertyName` or the factory supplied by your transformation context instead. */ const createComputedPropertyName: (expression: Expression) => ComputedPropertyName; /** @deprecated Use `factory.updateComputedPropertyName` or the factory supplied by your transformation context instead. */ diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 22af7579a0367..c445e4f11f49a 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -659,7 +659,7 @@ declare namespace ts { export interface QualifiedName extends Node { readonly kind: SyntaxKind.QualifiedName; readonly left: EntityName; - readonly right: Identifier; + readonly right: MemberName; } export type EntityName = Identifier | QualifiedName; export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName | PrivateIdentifier; @@ -3395,8 +3395,8 @@ declare namespace ts { createFalse(): FalseLiteral; createModifier(kind: T): ModifierToken; createModifiersFromModifierFlags(flags: ModifierFlags): Modifier[] | undefined; - createQualifiedName(left: EntityName, right: string | Identifier): QualifiedName; - updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier): QualifiedName; + createQualifiedName(left: EntityName, right: string | MemberName): QualifiedName; + updateQualifiedName(node: QualifiedName, left: EntityName, right: MemberName): QualifiedName; createComputedPropertyName(expression: Expression): ComputedPropertyName; updateComputedPropertyName(node: ComputedPropertyName, expression: Expression): ComputedPropertyName; createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration; @@ -6952,9 +6952,9 @@ declare namespace ts { /** @deprecated Use `factory.createModifiersFromModifierFlags` or the factory supplied by your transformation context instead. */ const createModifiersFromModifierFlags: (flags: ModifierFlags) => Modifier[] | undefined; /** @deprecated Use `factory.createQualifiedName` or the factory supplied by your transformation context instead. */ - const createQualifiedName: (left: EntityName, right: string | Identifier) => QualifiedName; + const createQualifiedName: (left: EntityName, right: string | MemberName) => QualifiedName; /** @deprecated Use `factory.updateQualifiedName` or the factory supplied by your transformation context instead. */ - const updateQualifiedName: (node: QualifiedName, left: EntityName, right: Identifier) => QualifiedName; + const updateQualifiedName: (node: QualifiedName, left: EntityName, right: MemberName) => QualifiedName; /** @deprecated Use `factory.createComputedPropertyName` or the factory supplied by your transformation context instead. */ const createComputedPropertyName: (expression: Expression) => ComputedPropertyName; /** @deprecated Use `factory.updateComputedPropertyName` or the factory supplied by your transformation context instead. */