@@ -5860,6 +5860,32 @@ namespace ts {
5860
5860
return typeToTypeNodeHelper(type, context);
5861
5861
}
5862
5862
5863
+ function trackExistingEntityName<T extends EntityNameOrEntityNameExpression>(node: T, context: NodeBuilderContext, includePrivateSymbol?: (s: Symbol) => void) {
5864
+ let introducesError = false;
5865
+ const leftmost = getFirstIdentifier(node);
5866
+ if (isInJSFile(node) && (isExportsIdentifier(leftmost) || isModuleExportsAccessExpression(leftmost.parent) || (isQualifiedName(leftmost.parent) && isModuleIdentifier(leftmost.parent.left) && isExportsIdentifier(leftmost.parent.right)))) {
5867
+ introducesError = true;
5868
+ return { introducesError, node };
5869
+ }
5870
+ const sym = resolveEntityName(leftmost, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveALias*/ true);
5871
+ if (sym) {
5872
+ if (isSymbolAccessible(sym, context.enclosingDeclaration, SymbolFlags.All, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible) {
5873
+ introducesError = true;
5874
+ }
5875
+ else {
5876
+ context.tracker?.trackSymbol?.(sym, context.enclosingDeclaration, SymbolFlags.All);
5877
+ includePrivateSymbol?.(sym);
5878
+ }
5879
+ if (isIdentifier(node)) {
5880
+ const name = sym.flags & SymbolFlags.TypeParameter ? typeParameterToName(getDeclaredTypeOfSymbol(sym), context) : factory.cloneNode(node);
5881
+ name.symbol = sym; // for quickinfo, which uses identifier symbol information
5882
+ return { introducesError, node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping) };
5883
+ }
5884
+ }
5885
+
5886
+ return { introducesError, node };
5887
+ }
5888
+
5863
5889
function serializeExistingTypeNode(context: NodeBuilderContext, existing: TypeNode, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) {
5864
5890
if (cancellationToken && cancellationToken.throwIfCancellationRequested) {
5865
5891
cancellationToken.throwIfCancellationRequested();
@@ -5983,25 +6009,10 @@ namespace ts {
5983
6009
}
5984
6010
5985
6011
if (isEntityName(node) || isEntityNameExpression(node)) {
5986
- const leftmost = getFirstIdentifier(node);
5987
- if (isInJSFile(node) && (isExportsIdentifier(leftmost) || isModuleExportsAccessExpression(leftmost.parent) || (isQualifiedName(leftmost.parent) && isModuleIdentifier(leftmost.parent.left) && isExportsIdentifier(leftmost.parent.right)))) {
5988
- hadError = true;
5989
- return node;
5990
- }
5991
- const sym = resolveEntityName(leftmost, SymbolFlags.All, /*ignoreErrors*/ true, /*dontResolveALias*/ true);
5992
- if (sym) {
5993
- if (isSymbolAccessible(sym, context.enclosingDeclaration, SymbolFlags.All, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible) {
5994
- hadError = true;
5995
- }
5996
- else {
5997
- context.tracker?.trackSymbol?.(sym, context.enclosingDeclaration, SymbolFlags.All);
5998
- includePrivateSymbol?.(sym);
5999
- }
6000
- if (isIdentifier(node)) {
6001
- const name = sym.flags & SymbolFlags.TypeParameter ? typeParameterToName(getDeclaredTypeOfSymbol(sym), context) : factory.cloneNode(node);
6002
- name.symbol = sym; // for quickinfo, which uses identifier symbol information
6003
- return setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping);
6004
- }
6012
+ const { introducesError, node: result } = trackExistingEntityName(node, context, includePrivateSymbol);
6013
+ hadError = hadError || introducesError;
6014
+ if (result !== node) {
6015
+ return result;
6005
6016
}
6006
6017
}
6007
6018
@@ -6732,12 +6743,50 @@ namespace ts {
6732
6743
!(p.flags & SymbolFlags.Prototype || p.escapedName === "prototype" || p.valueDeclaration && getEffectiveModifierFlags(p.valueDeclaration) & ModifierFlags.Static && isClassLike(p.valueDeclaration.parent));
6733
6744
}
6734
6745
6746
+ function sanitizeJSDocImplements(clauses: readonly ExpressionWithTypeArguments[]): ExpressionWithTypeArguments[] | undefined {
6747
+ const result = mapDefined(clauses, e => {
6748
+ const oldEnclosing = context.enclosingDeclaration;
6749
+ context.enclosingDeclaration = e;
6750
+ let expr = e.expression;
6751
+ if (isEntityNameExpression(expr)) {
6752
+ if (isIdentifier(expr) && idText(expr) === "") {
6753
+ return cleanup(/*result*/ undefined); // Empty heritage clause, should be an error, but prefer emitting no heritage clauses to reemitting the empty one
6754
+ }
6755
+ let introducesError: boolean;
6756
+ ({ introducesError, node: expr } = trackExistingEntityName(expr, context, includePrivateSymbol));
6757
+ if (introducesError) {
6758
+ return cleanup(/*result*/ undefined);
6759
+ }
6760
+ }
6761
+ return cleanup(factory.createExpressionWithTypeArguments(expr,
6762
+ map(e.typeArguments, a =>
6763
+ serializeExistingTypeNode(context, a, includePrivateSymbol, bundled)
6764
+ || typeToTypeNodeHelper(getTypeFromTypeNode(a), context)
6765
+ )
6766
+ ));
6767
+
6768
+ function cleanup<T>(result: T): T {
6769
+ context.enclosingDeclaration = oldEnclosing;
6770
+ return result;
6771
+ }
6772
+ });
6773
+ if (result.length === clauses.length) {
6774
+ return result;
6775
+ }
6776
+ return undefined;
6777
+ }
6778
+
6735
6779
function serializeAsClass(symbol: Symbol, localName: string, modifierFlags: ModifierFlags) {
6780
+ const originalDecl = find(symbol.declarations, isClassLike);
6781
+ const oldEnclosing = context.enclosingDeclaration;
6782
+ context.enclosingDeclaration = originalDecl || oldEnclosing;
6736
6783
const localParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
6737
6784
const typeParamDecls = map(localParams, p => typeParameterToDeclaration(p, context));
6738
6785
const classType = getDeclaredTypeOfClassOrInterface(symbol);
6739
6786
const baseTypes = getBaseTypes(classType);
6740
- const implementsExpressions = mapDefined(getImplementsTypes(classType), serializeImplementedType);
6787
+ const originalImplements = originalDecl && getEffectiveImplementsTypeNodes(originalDecl);
6788
+ const implementsExpressions = originalImplements && sanitizeJSDocImplements(originalImplements)
6789
+ || mapDefined(getImplementsTypes(classType), serializeImplementedType);
6741
6790
const staticType = getTypeOfSymbol(symbol);
6742
6791
const isClass = !!staticType.symbol?.valueDeclaration && isClassLike(staticType.symbol.valueDeclaration);
6743
6792
const staticBaseType = isClass
@@ -6790,6 +6839,7 @@ namespace ts {
6790
6839
[factory.createConstructorDeclaration(/*decorators*/ undefined, factory.createModifiersFromModifierFlags(ModifierFlags.Private), [], /*body*/ undefined)] :
6791
6840
serializeSignatures(SignatureKind.Construct, staticType, staticBaseType, SyntaxKind.Constructor) as ConstructorDeclaration[];
6792
6841
const indexSignatures = serializeIndexSignatures(classType, baseTypes[0]);
6842
+ context.enclosingDeclaration = oldEnclosing;
6793
6843
addResult(setTextRange(factory.createClassDeclaration(
6794
6844
/*decorators*/ undefined,
6795
6845
/*modifiers*/ undefined,
0 commit comments