Skip to content
109 changes: 89 additions & 20 deletions src/compiler/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2181,51 +2181,120 @@ namespace ts {

// JSDoc

/* @internal */
function createJSDocTag<T extends JSDocTag>(kind: T["kind"], tagName: string, comment?: string): T {
const node = createSynthesizedNode(kind) as T;
node.tagName = createIdentifier(tagName);
node.comment = comment;
return node;
}

function createJSDocTagWithTypeExpression<T extends JSDocTag & { typeExpression?: TypeNode }>(kind: T["kind"], tagName: string, typeExpression?: TypeNode, comment?: string) {
const node = createJSDocTag<T>(kind, tagName, comment);
node.typeExpression = typeExpression;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK the factory functions should set properties in the same order as the parser to avoid multiple shapes of the same object.
Looking at parseReturnTag as an example: it sets tagName, typeExpression and comment (in parseTag function).

Maybe you want to change the parser to initialize the properties in the same order as the newly added factories (comment before typeExpression and so on)

Copy link
Contributor Author

@Kingwl Kingwl Jan 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, I also have concerns about this, I decide to remove this helper function.😢

return node;
}

export function createJSDocTypeExpression(type: TypeNode): JSDocTypeExpression {
const node = createSynthesizedNode(SyntaxKind.JSDocTypeExpression) as JSDocTypeExpression;
node.type = type;
return node;
}

/* @internal */
export function createJSDocTypeTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocTypeTag {
const tag = createJSDocTag<JSDocTypeTag>(SyntaxKind.JSDocTypeTag, "type");
tag.typeExpression = typeExpression;
tag.comment = comment;
return tag;
return createJSDocTagWithTypeExpression<JSDocTypeTag>(SyntaxKind.JSDocTypeTag, "type", typeExpression, comment);
}

/* @internal */
export function createJSDocReturnTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocReturnTag {
const tag = createJSDocTag<JSDocReturnTag>(SyntaxKind.JSDocReturnTag, "returns");
tag.typeExpression = typeExpression;
tag.comment = comment;
return tag;
return createJSDocTagWithTypeExpression<JSDocReturnTag>(SyntaxKind.JSDocReturnTag, "returns", typeExpression, comment);
}

/* @internal */
export function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
const tag = createJSDocTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, "param");
tag.typeExpression = typeExpression;
const tag = createJSDocTagWithTypeExpression<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, "param", typeExpression, comment);
tag.name = name;
tag.isBracketed = isBracketed;
tag.comment = comment;
return tag;
}

/* @internal */
export function createJSDocComment(comment?: string | undefined, tags?: NodeArray<JSDocTag> | undefined) {
const node = createSynthesizedNode(SyntaxKind.JSDocComment) as JSDoc;
node.comment = comment;
node.tags = tags;
return node;
}

/* @internal */
function createJSDocTag<T extends JSDocTag>(kind: T["kind"], tagName: string): T {
const node = createSynthesizedNode(kind) as T;
node.tagName = createIdentifier(tagName);
export function createJSDocAugmentsTag(tagName: "augments" | "extends", classExpression: JSDocAugmentsTag["class"], comment?: string) {
const node = createJSDocTag<JSDocAugmentsTag>(SyntaxKind.JSDocAugmentsTag, tagName, comment);
node.class = classExpression;
return node;
}

export function createJSDocClassTag(tagName: "class" | "constructor", comment?: string) {
return createJSDocTag<JSDocClassTag>(SyntaxKind.JSDocClassTag, tagName, comment);
}

export function createJSDocEnumTag(typeExpression?: JSDocTypeExpression, comment?: string) {
return createJSDocTagWithTypeExpression<JSDocEnumTag>(SyntaxKind.JSDocEnumTag, "enum", typeExpression, comment);
}

export function createJSDocThisTag(typeExpression?: JSDocTypeExpression, comment?: string) {
return createJSDocTagWithTypeExpression<JSDocThisTag>(SyntaxKind.JSDocThisTag, "this", typeExpression, comment);
}

export function createJSDocTemplateTag(typeParameters: ReadonlyArray<TypeParameterDeclaration>, constraint?: JSDocTypeExpression, comment?: string) {
const node = createJSDocTag<JSDocTemplateTag>(SyntaxKind.JSDocTemplateTag, "template", comment);
node.constraint = constraint;
node.typeParameters = asNodeArray(typeParameters);
return node;
}

export function createJSDocTypedefTag(fullName?: JSDocNamespaceDeclaration | Identifier, name?: Identifier, typeExpression?: JSDocTypeExpression | JSDocTypeLiteral, comment?: string) {
const node = createJSDocTagWithTypeExpression<JSDocTypedefTag>(SyntaxKind.JSDocTypedefTag, "typedef", typeExpression, comment);
node.fullName = fullName;
node.name = name;
return node;
}

export function createJSDocCallbackTag(typeExpression: JSDocSignature, fullName?: JSDocNamespaceDeclaration | Identifier, name?: Identifier, comment?: string) {
const node = createJSDocTagWithTypeExpression<JSDocCallbackTag>(SyntaxKind.JSDocCallbackTag, "callback", typeExpression, comment);
node.fullName = fullName;
node.name = name;
return node;
}

export function createJSDocSignature(parameters: ReadonlyArray<JSDocParameterTag>, type?: JSDocReturnTag, typeParameters?: ReadonlyArray<JSDocTemplateTag>) {
const node = createSynthesizedNode(SyntaxKind.JSDocSignature) as JSDocSignature;
node.parameters = parameters;
node.typeParameters = typeParameters;
node.type = type;
return node;
}

function createJSDocPropertyLikeTag<T extends JSDocPropertyLikeTag>(kind: T["kind"], tagName: "arg" | "argument" | "param", name: EntityName, isNameFirst: boolean, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string) {
const node = createJSDocTagWithTypeExpression<T>(kind, tagName, typeExpression);
node.name = name;
node.isNameFirst = isNameFirst;
node.isBracketed = isBracketed;
node.comment = comment;
return node;
}

export function createJSDocPropertyTag(tagName: "arg" | "argument" | "param", name: EntityName, isNameFirst: boolean, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string) {
return createJSDocPropertyLikeTag<JSDocPropertyTag>(SyntaxKind.JSDocPropertyTag, tagName, name, isNameFirst, isBracketed, typeExpression, comment);
}

export function createJSDocParameterTag(tagName: "arg" | "argument" | "param", name: EntityName, isNameFirst: boolean, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string) {
return createJSDocPropertyLikeTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, tagName, name, isNameFirst, isBracketed, typeExpression, comment);
}

export function createJSDocTypeLiteral(jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>, isArrayType?: boolean) {
const node = createSynthesizedNode(SyntaxKind.JSDocTypeLiteral) as JSDocTypeLiteral;
node.jsDocPropertyTags = jsDocPropertyTags;
node.isArrayType = isArrayType;
return node;
}

export function appendJSDocToContainer(node: JSDocContainer, jsdoc: JSDoc) {
node.jsDoc = append(node.jsDoc, jsdoc);
return node;
}

Expand Down
17 changes: 17 additions & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3918,6 +3918,23 @@ declare namespace ts {
function updateExportSpecifier(node: ExportSpecifier, propertyName: Identifier | undefined, name: Identifier): ExportSpecifier;
function createExternalModuleReference(expression: Expression): ExternalModuleReference;
function updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference;
function createJSDocTypeExpression(type: TypeNode): JSDocTypeExpression;
function createJSDocTypeTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocTypeTag;
function createJSDocReturnTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocReturnTag;
function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag;
function createJSDocComment(comment?: string | undefined, tags?: NodeArray<JSDocTag> | undefined): JSDoc;
function createJSDocAugmentsTag(tagName: "augments" | "extends", classExpression: JSDocAugmentsTag["class"], comment?: string): JSDocAugmentsTag;
function createJSDocClassTag(tagName: "class" | "constructor", comment?: string): JSDocClassTag;
function createJSDocEnumTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocEnumTag;
function createJSDocThisTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocThisTag;
function createJSDocTemplateTag(typeParameters: ReadonlyArray<TypeParameterDeclaration>, constraint?: JSDocTypeExpression, comment?: string): JSDocTemplateTag;
function createJSDocTypedefTag(fullName?: JSDocNamespaceDeclaration | Identifier, name?: Identifier, typeExpression?: JSDocTypeExpression | JSDocTypeLiteral, comment?: string): JSDocTypedefTag;
function createJSDocCallbackTag(typeExpression: JSDocSignature, fullName?: JSDocNamespaceDeclaration | Identifier, name?: Identifier, comment?: string): JSDocCallbackTag;
function createJSDocSignature(parameters: ReadonlyArray<JSDocParameterTag>, type?: JSDocReturnTag, typeParameters?: ReadonlyArray<JSDocTemplateTag>): JSDocSignature;
function createJSDocPropertyTag(tagName: "arg" | "argument" | "param", name: EntityName, isNameFirst: boolean, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocPropertyTag;
function createJSDocParameterTag(tagName: "arg" | "argument" | "param", name: EntityName, isNameFirst: boolean, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag;
function createJSDocTypeLiteral(jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>, isArrayType?: boolean): JSDocTypeLiteral;
function appendJSDocToContainer(node: JSDocContainer, jsdoc: JSDoc): JSDocContainer;
function createJsxElement(openingElement: JsxOpeningElement, children: ReadonlyArray<JsxChild>, closingElement: JsxClosingElement): JsxElement;
function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: ReadonlyArray<JsxChild>, closingElement: JsxClosingElement): JsxElement;
function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray<TypeNode> | undefined, attributes: JsxAttributes): JsxSelfClosingElement;
Expand Down
17 changes: 17 additions & 0 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3918,6 +3918,23 @@ declare namespace ts {
function updateExportSpecifier(node: ExportSpecifier, propertyName: Identifier | undefined, name: Identifier): ExportSpecifier;
function createExternalModuleReference(expression: Expression): ExternalModuleReference;
function updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference;
function createJSDocTypeExpression(type: TypeNode): JSDocTypeExpression;
function createJSDocTypeTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocTypeTag;
function createJSDocReturnTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocReturnTag;
function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag;
function createJSDocComment(comment?: string | undefined, tags?: NodeArray<JSDocTag> | undefined): JSDoc;
function createJSDocAugmentsTag(tagName: "augments" | "extends", classExpression: JSDocAugmentsTag["class"], comment?: string): JSDocAugmentsTag;
function createJSDocClassTag(tagName: "class" | "constructor", comment?: string): JSDocClassTag;
function createJSDocEnumTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocEnumTag;
function createJSDocThisTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocThisTag;
function createJSDocTemplateTag(typeParameters: ReadonlyArray<TypeParameterDeclaration>, constraint?: JSDocTypeExpression, comment?: string): JSDocTemplateTag;
function createJSDocTypedefTag(fullName?: JSDocNamespaceDeclaration | Identifier, name?: Identifier, typeExpression?: JSDocTypeExpression | JSDocTypeLiteral, comment?: string): JSDocTypedefTag;
function createJSDocCallbackTag(typeExpression: JSDocSignature, fullName?: JSDocNamespaceDeclaration | Identifier, name?: Identifier, comment?: string): JSDocCallbackTag;
function createJSDocSignature(parameters: ReadonlyArray<JSDocParameterTag>, type?: JSDocReturnTag, typeParameters?: ReadonlyArray<JSDocTemplateTag>): JSDocSignature;
function createJSDocPropertyTag(tagName: "arg" | "argument" | "param", name: EntityName, isNameFirst: boolean, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocPropertyTag;
function createJSDocParameterTag(tagName: "arg" | "argument" | "param", name: EntityName, isNameFirst: boolean, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag;
function createJSDocTypeLiteral(jsDocPropertyTags?: ReadonlyArray<JSDocPropertyLikeTag>, isArrayType?: boolean): JSDocTypeLiteral;
function appendJSDocToContainer(node: JSDocContainer, jsdoc: JSDoc): JSDocContainer;
function createJsxElement(openingElement: JsxOpeningElement, children: ReadonlyArray<JsxChild>, closingElement: JsxClosingElement): JsxElement;
function updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: ReadonlyArray<JsxChild>, closingElement: JsxClosingElement): JsxElement;
function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray<TypeNode> | undefined, attributes: JsxAttributes): JsxSelfClosingElement;
Expand Down