Avoid mutating SymbolObject.prototype in services

This commit is contained in:
Ron Buckton
2024-04-15 17:09:16 -04:00
parent 90a5def2c8
commit d1ae0e85c8
3 changed files with 91 additions and 65 deletions
+9 -16
View File
@@ -42,6 +42,7 @@ import {
UnionOrIntersectionType,
UnionType,
} from "./_namespaces/ts";
import { SymbolObjectInternals } from "./symbolObjectInternals";
/** @internal */
export class SymbolObject implements Symbol {
@@ -76,14 +77,6 @@ export class SymbolObject implements Symbol {
declare assignmentDeclarationMembers?: Map<number, Declaration>;
declare globalExports?: SymbolTable;
// TODO: Added by services, review for migration/polymorphism:
// documentationComment?: SymbolDisplayPart[];
// tags?: JSDocTagInfo[]; // same
// contextualGetAccessorDocumentationComment?: SymbolDisplayPart[];
// contextualSetAccessorDocumentationComment?: SymbolDisplayPart[];
// contextualGetAccessorTags?: JSDocTagInfo[];
// contextualSetAccessorTags?: JSDocTagInfo[];
constructor(flags: SymbolFlags, name: __String) {
this.flags = flags;
this.escapedName = name;
@@ -109,20 +102,20 @@ export class SymbolObject implements Symbol {
return this.declarations;
}
getDocumentationComment(_checker: TypeChecker | undefined): SymbolDisplayPart[] {
throw new TypeError("Not implemented.");
getDocumentationComment(checker: TypeChecker | undefined): SymbolDisplayPart[] {
return SymbolObjectInternals.internals.getDocumentationComment(this, checker);
}
getContextualDocumentationComment(_context: Node | undefined, _checker: TypeChecker | undefined): SymbolDisplayPart[] {
throw new TypeError("Not implemented.");
getContextualDocumentationComment(context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] {
return SymbolObjectInternals.internals.getContextualDocumentationComment(this, context, checker);
}
getJsDocTags(_checker?: TypeChecker): JSDocTagInfo[] {
throw new TypeError("Not implemented.");
getJsDocTags(checker?: TypeChecker): JSDocTagInfo[] {
return SymbolObjectInternals.internals.getJsDocTags(this, checker);
}
getContextualJsDocTags(_context: Node | undefined, _checker: TypeChecker | undefined): JSDocTagInfo[] {
throw new TypeError("Not implemented.");
getContextualJsDocTags(context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] {
return SymbolObjectInternals.internals.getContextualJsDocTags(this, context, checker);
}
}
+27
View File
@@ -0,0 +1,27 @@
import { SymbolObject } from "./objectConstructors";
import { JSDocTagInfo, Node, SymbolDisplayPart, TypeChecker } from "./types";
/** @internal */
export class SymbolObjectInternals {
static internals = new SymbolObjectInternals();
getDocumentationComment(symbol: SymbolObject, typeChecker: TypeChecker | undefined): SymbolDisplayPart[];
getDocumentationComment(_symbol: SymbolObject, _typeChecker: TypeChecker | undefined): SymbolDisplayPart[] {
throw new TypeError("Not implemented.");
}
getContextualDocumentationComment(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[];
getContextualDocumentationComment(_symbol: SymbolObject, _context: Node | undefined, _checker: TypeChecker | undefined): SymbolDisplayPart[] {
throw new TypeError("Not implemented.");
}
getJsDocTags(symbol: SymbolObject, checker?: TypeChecker): JSDocTagInfo[];
getJsDocTags(_symbol: SymbolObject, _checker?: TypeChecker): JSDocTagInfo[] {
throw new TypeError("Not implemented.");
}
getContextualJsDocTags(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[];
getContextualJsDocTags(_symbol: SymbolObject, _context: Node | undefined, _checker: TypeChecker | undefined): JSDocTagInfo[] {
throw new TypeError("Not implemented.");
}
}
+55 -49
View File
@@ -2,6 +2,7 @@ import {
SignatureObject,
SymbolObject,
} from "../compiler/objectConstructors";
import { SymbolObjectInternals } from "../compiler/symbolObjectInternals";
import {
__String,
ApplicableRefactorInfo,
@@ -290,64 +291,69 @@ function ensureSymbolExtraFields(symbol: Symbol) {
return extra;
}
SymbolObject.prototype.getDocumentationComment = function (this: Symbol | TransientSymbol, checker: TypeChecker | undefined): SymbolDisplayPart[] {
const extra = ensureSymbolExtraFields(this);
if (!extra.documentationComment) {
extra.documentationComment = emptyArray; // Set temporarily to avoid an infinite loop finding inherited docs
class ServicesSymbolObjectInternals extends SymbolObjectInternals {
override getDocumentationComment(symbol: SymbolObject, checker: TypeChecker | undefined): SymbolDisplayPart[] {
const extra = ensureSymbolExtraFields(symbol);
if (!extra.documentationComment) {
extra.documentationComment = emptyArray; // Set temporarily to avoid an infinite loop finding inherited docs
if (!this.declarations && isTransientSymbol(this) && this.links.target && isTransientSymbol(this.links.target) && this.links.target.links.tupleLabelDeclaration) {
const labelDecl = this.links.target.links.tupleLabelDeclaration;
extra.documentationComment = getDocumentationComment([labelDecl], checker);
}
else {
extra.documentationComment = getDocumentationComment(this.declarations, checker);
if (!symbol.declarations && isTransientSymbol(symbol) && symbol.links.target && isTransientSymbol(symbol.links.target) && symbol.links.target.links.tupleLabelDeclaration) {
const labelDecl = symbol.links.target.links.tupleLabelDeclaration;
extra.documentationComment = getDocumentationComment([labelDecl], checker);
}
else {
extra.documentationComment = getDocumentationComment(symbol.declarations, checker);
}
}
return extra.documentationComment;
}
return extra.documentationComment;
};
SymbolObject.prototype.getContextualDocumentationComment = function (this: Symbol, context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] {
if (context) {
const extra = ensureSymbolExtraFields(this);
if (isGetAccessor(context)) {
extra.contextualGetAccessorDocumentationComment ??= getDocumentationComment(filter(this.declarations, isGetAccessor), checker);
if (length(extra.contextualGetAccessorDocumentationComment)) {
return extra.contextualGetAccessorDocumentationComment;
}
}
else if (isSetAccessor(context)) {
extra.contextualSetAccessorDocumentationComment ??= getDocumentationComment(filter(this.declarations, isSetAccessor), checker);
if (length(extra.contextualSetAccessorDocumentationComment)) {
return extra.contextualSetAccessorDocumentationComment;
override getContextualDocumentationComment(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] {
if (context) {
const extra = ensureSymbolExtraFields(symbol);
if (isGetAccessor(context)) {
extra.contextualGetAccessorDocumentationComment ??= getDocumentationComment(filter(symbol.declarations, isGetAccessor), checker);
if (length(extra.contextualGetAccessorDocumentationComment)) {
return extra.contextualGetAccessorDocumentationComment;
}
}
else if (isSetAccessor(context)) {
extra.contextualSetAccessorDocumentationComment ??= getDocumentationComment(filter(symbol.declarations, isSetAccessor), checker);
if (length(extra.contextualSetAccessorDocumentationComment)) {
return extra.contextualSetAccessorDocumentationComment;
}
}
}
return this.getDocumentationComment(symbol, checker);
}
return this.getDocumentationComment(checker);
};
SymbolObject.prototype.getJsDocTags = function (this: Symbol, checker?: TypeChecker): JSDocTagInfo[] {
const extra = ensureSymbolExtraFields(this);
return extra.tags ??= getJsDocTagsOfDeclarations(this.declarations, checker);
};
SymbolObject.prototype.getContextualJsDocTags = function (this: Symbol, context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] {
if (context) {
const extra = ensureSymbolExtraFields(this);
if (isGetAccessor(context)) {
extra.contextualGetAccessorTags ??= getJsDocTagsOfDeclarations(filter(this.declarations, isGetAccessor), checker);
if (length(extra.contextualGetAccessorTags)) {
return extra.contextualGetAccessorTags;
}
}
else if (isSetAccessor(context)) {
extra.contextualSetAccessorTags ??= getJsDocTagsOfDeclarations(filter(this.declarations, isSetAccessor), checker);
if (length(extra.contextualSetAccessorTags)) {
return extra.contextualSetAccessorTags;
}
}
override getJsDocTags(symbol: SymbolObject, checker?: TypeChecker): JSDocTagInfo[] {
const extra = ensureSymbolExtraFields(symbol);
return extra.tags ??= getJsDocTagsOfDeclarations(symbol.declarations, checker);
}
return this.getJsDocTags(checker);
};
override getContextualJsDocTags(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] {
if (context) {
const extra = ensureSymbolExtraFields(symbol);
if (isGetAccessor(context)) {
extra.contextualGetAccessorTags ??= getJsDocTagsOfDeclarations(filter(symbol.declarations, isGetAccessor), checker);
if (length(extra.contextualGetAccessorTags)) {
return extra.contextualGetAccessorTags;
}
}
else if (isSetAccessor(context)) {
extra.contextualSetAccessorTags ??= getJsDocTagsOfDeclarations(filter(symbol.declarations, isSetAccessor), checker);
if (length(extra.contextualSetAccessorTags)) {
return extra.contextualSetAccessorTags;
}
}
}
return this.getJsDocTags(symbol, checker);
}
}
// Override the internals for symbols
SymbolObjectInternals.internals = new ServicesSymbolObjectInternals();
interface SignatureExtraFields {
// Undefined is used to indicate the value has not been computed. If, after computing, the