mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-16 07:13:45 -05:00
Merge existing JSDoc comments (#27978)
* Correct indentation, using correct (I hope) indentation code Note that part of the code, in formatting.ts, is cloned but should be extracted to a function instead. * Remove some possibly-superfluous code But I see 4 failures with whitespace, so perhaps not. * Restrict indentation change to avoid breaking baselines The indentation code is very complex so I'm just going to avoid breaking our single-line tests for now, plus add a simple jsdoc test to show that multiline jsdoc indentation isn't destroyed in the common case. * Switched over to construction for @return/@type Still doesn't merge correctly though * Add @return tags to emitter * Merge multiple jsdocs (not for @param yet) * Merge multiple jsdoc for parameters too * Emit more jsdoc tags Not all of them; I got cold feet since I'll have to write tests for them. I'll do that tomorrow. * Many fixes to JSDoc emit And single tests (at least) for all tags * Cleanup in textChanges.ts * Cleanup in formatting.ts (Plus a little more in textChanges.ts) * Cleanup in inferFromUsage.ts * Fix minor omissions * Separate merged top-level JSDoc comments with \n instead of space. * Don't delete intrusive non-jsdoc comments * Cleanup from PR comments 1. Refactor emit code into smaller functions. 2. Preceding-whitespace utility is slightly easier to use. 3. Better casts and types in inferFromUsage make it easier to read. * Fix bogus newline * Use @andy-ms' cleanup annotateJSDocParameters
This commit is contained in:
committed by
GitHub
parent
e46c846ee6
commit
fe2a33fcbc
@@ -862,7 +862,34 @@ namespace ts {
|
||||
case SyntaxKind.EnumMember:
|
||||
return emitEnumMember(<EnumMember>node);
|
||||
|
||||
// JSDoc nodes (ignored)
|
||||
// JSDoc nodes (only used in codefixes currently)
|
||||
case SyntaxKind.JSDocParameterTag:
|
||||
case SyntaxKind.JSDocPropertyTag:
|
||||
return emitJSDocPropertyLikeTag(node as JSDocPropertyLikeTag);
|
||||
case SyntaxKind.JSDocReturnTag:
|
||||
case SyntaxKind.JSDocTypeTag:
|
||||
case SyntaxKind.JSDocThisTag:
|
||||
case SyntaxKind.JSDocEnumTag:
|
||||
return emitJSDocSimpleTypedTag(node as JSDocTypeTag);
|
||||
case SyntaxKind.JSDocAugmentsTag:
|
||||
return emitJSDocAugmentsTag(node as JSDocAugmentsTag);
|
||||
case SyntaxKind.JSDocTemplateTag:
|
||||
return emitJSDocTemplateTag(node as JSDocTemplateTag);
|
||||
case SyntaxKind.JSDocTypedefTag:
|
||||
return emitJSDocTypedefTag(node as JSDocTypedefTag);
|
||||
case SyntaxKind.JSDocCallbackTag:
|
||||
return emitJSDocCallbackTag(node as JSDocCallbackTag);
|
||||
case SyntaxKind.JSDocSignature:
|
||||
return emitJSDocSignature(node as JSDocSignature);
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
return emitJSDocTypeLiteral(node as JSDocTypeLiteral);
|
||||
case SyntaxKind.JSDocClassTag:
|
||||
case SyntaxKind.JSDocTag:
|
||||
return emitJSDocSimpleTag(node as JSDocTag);
|
||||
|
||||
case SyntaxKind.JSDocComment:
|
||||
return emitJSDoc(node as JSDoc);
|
||||
|
||||
// Transformation nodes (ignored)
|
||||
}
|
||||
|
||||
@@ -2584,6 +2611,154 @@ namespace ts {
|
||||
emitInitializer(node.initializer, node.name.end, node);
|
||||
}
|
||||
|
||||
//
|
||||
// JSDoc
|
||||
//
|
||||
function emitJSDoc(node: JSDoc) {
|
||||
write("/**");
|
||||
if (node.comment) {
|
||||
const lines = node.comment.split(/\r\n?|\n/g);
|
||||
for (const line of lines) {
|
||||
writeLine();
|
||||
writeSpace();
|
||||
writePunctuation("*");
|
||||
writeSpace();
|
||||
write(line);
|
||||
}
|
||||
}
|
||||
if (node.tags) {
|
||||
if (node.tags.length === 1 && node.tags[0].kind === SyntaxKind.JSDocTypeTag && !node.comment) {
|
||||
writeSpace();
|
||||
emit(node.tags[0]);
|
||||
}
|
||||
else {
|
||||
emitList(node, node.tags, ListFormat.JSDocComment);
|
||||
}
|
||||
}
|
||||
writeSpace();
|
||||
write("*/");
|
||||
}
|
||||
|
||||
function emitJSDocSimpleTypedTag(tag: JSDocTypeTag | JSDocThisTag | JSDocEnumTag | JSDocReturnTag) {
|
||||
emitJSDocTagName(tag.tagName);
|
||||
emitJSDocTypeExpression(tag.typeExpression);
|
||||
emitJSDocComment(tag.comment);
|
||||
}
|
||||
|
||||
function emitJSDocAugmentsTag(tag: JSDocAugmentsTag) {
|
||||
emitJSDocTagName(tag.tagName);
|
||||
writeSpace();
|
||||
writePunctuation("{");
|
||||
emit(tag.class);
|
||||
writePunctuation("}");
|
||||
emitJSDocComment(tag.comment);
|
||||
}
|
||||
|
||||
function emitJSDocTemplateTag(tag: JSDocTemplateTag) {
|
||||
emitJSDocTagName(tag.tagName);
|
||||
emitJSDocTypeExpression(tag.constraint);
|
||||
writeSpace();
|
||||
emitList(tag, tag.typeParameters, ListFormat.CommaListElements);
|
||||
emitJSDocComment(tag.comment);
|
||||
}
|
||||
|
||||
function emitJSDocTypedefTag(tag: JSDocTypedefTag) {
|
||||
emitJSDocTagName(tag.tagName);
|
||||
if (tag.typeExpression) {
|
||||
if (tag.typeExpression.kind === SyntaxKind.JSDocTypeExpression) {
|
||||
emitJSDocTypeExpression(tag.typeExpression);
|
||||
}
|
||||
else {
|
||||
writeSpace();
|
||||
writePunctuation("{");
|
||||
write("Object");
|
||||
if (tag.typeExpression.isArrayType) {
|
||||
writePunctuation("[");
|
||||
writePunctuation("]");
|
||||
}
|
||||
writePunctuation("}");
|
||||
}
|
||||
}
|
||||
if (tag.fullName) {
|
||||
writeSpace();
|
||||
emit(tag.fullName);
|
||||
}
|
||||
emitJSDocComment(tag.comment);
|
||||
if (tag.typeExpression && tag.typeExpression.kind === SyntaxKind.JSDocTypeLiteral) {
|
||||
emitJSDocTypeLiteral(tag.typeExpression);
|
||||
}
|
||||
}
|
||||
|
||||
function emitJSDocCallbackTag(tag: JSDocCallbackTag) {
|
||||
emitJSDocTagName(tag.tagName);
|
||||
if (tag.name) {
|
||||
writeSpace();
|
||||
emit(tag.name);
|
||||
}
|
||||
emitJSDocComment(tag.comment);
|
||||
emitJSDocSignature(tag.typeExpression);
|
||||
}
|
||||
|
||||
function emitJSDocSimpleTag(tag: JSDocTag) {
|
||||
emitJSDocTagName(tag.tagName);
|
||||
emitJSDocComment(tag.comment);
|
||||
}
|
||||
|
||||
function emitJSDocTypeLiteral(lit: JSDocTypeLiteral) {
|
||||
emitList(lit, createNodeArray(lit.jsDocPropertyTags), ListFormat.JSDocComment);
|
||||
}
|
||||
|
||||
function emitJSDocSignature(sig: JSDocSignature) {
|
||||
if (sig.typeParameters) {
|
||||
emitList(sig, createNodeArray(sig.typeParameters), ListFormat.JSDocComment);
|
||||
}
|
||||
if (sig.parameters) {
|
||||
emitList(sig, createNodeArray(sig.parameters), ListFormat.JSDocComment);
|
||||
}
|
||||
if (sig.type) {
|
||||
writeLine();
|
||||
writeSpace();
|
||||
writePunctuation("*");
|
||||
writeSpace();
|
||||
emit(sig.type);
|
||||
}
|
||||
}
|
||||
|
||||
function emitJSDocPropertyLikeTag(param: JSDocPropertyLikeTag) {
|
||||
emitJSDocTagName(param.tagName);
|
||||
emitJSDocTypeExpression(param.typeExpression);
|
||||
writeSpace();
|
||||
if (param.isBracketed) {
|
||||
writePunctuation("[");
|
||||
}
|
||||
emit(param.name);
|
||||
if (param.isBracketed) {
|
||||
writePunctuation("]");
|
||||
}
|
||||
emitJSDocComment(param.comment);
|
||||
}
|
||||
|
||||
function emitJSDocTagName(tagName: Identifier) {
|
||||
writePunctuation("@");
|
||||
emit(tagName);
|
||||
}
|
||||
|
||||
function emitJSDocComment(comment: string | undefined) {
|
||||
if (comment) {
|
||||
writeSpace();
|
||||
write(comment);
|
||||
}
|
||||
}
|
||||
|
||||
function emitJSDocTypeExpression(typeExpression: JSDocTypeExpression | undefined) {
|
||||
if (typeExpression) {
|
||||
writeSpace();
|
||||
writePunctuation("{");
|
||||
emit(typeExpression.type);
|
||||
writePunctuation("}");
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Top-level nodes
|
||||
//
|
||||
@@ -2875,6 +3050,11 @@ namespace ts {
|
||||
writeSpace();
|
||||
writePunctuation("|");
|
||||
break;
|
||||
case ListFormat.AsteriskDelimited:
|
||||
writeSpace();
|
||||
writePunctuation("*");
|
||||
writeSpace();
|
||||
break;
|
||||
case ListFormat.AmpersandDelimited:
|
||||
writeSpace();
|
||||
writePunctuation("&");
|
||||
@@ -2944,7 +3124,12 @@ namespace ts {
|
||||
const child = children![start + i];
|
||||
|
||||
// Write the delimiter if this is not the first node.
|
||||
if (previousSibling) {
|
||||
if (format & ListFormat.AsteriskDelimited) {
|
||||
// always write JSDoc in the format "\n *"
|
||||
writeLine();
|
||||
writeDelimiter(format);
|
||||
}
|
||||
else if (previousSibling) {
|
||||
// i.e
|
||||
// function commentedParameters(
|
||||
// /* Parameter a */
|
||||
|
||||
@@ -2170,6 +2170,57 @@ namespace ts {
|
||||
: node;
|
||||
}
|
||||
|
||||
// JSDoc
|
||||
|
||||
/* @internal */
|
||||
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;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createJSDocReturnTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocReturnTag {
|
||||
const tag = createJSDocTag<JSDocReturnTag>(SyntaxKind.JSDocReturnTag, "returns");
|
||||
tag.typeExpression = typeExpression;
|
||||
tag.comment = comment;
|
||||
return tag;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
|
||||
const tag = createJSDocTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, "param");
|
||||
tag.typeExpression = typeExpression;
|
||||
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.atToken = createToken(SyntaxKind.AtToken);
|
||||
node.tagName = createIdentifier(tagName);
|
||||
return node;
|
||||
}
|
||||
|
||||
// JSX
|
||||
|
||||
export function createJsxElement(openingElement: JsxOpeningElement, children: ReadonlyArray<JsxChild>, closingElement: JsxClosingElement) {
|
||||
|
||||
@@ -2447,7 +2447,7 @@ namespace ts {
|
||||
|
||||
export interface JSDocTemplateTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocTemplateTag;
|
||||
constraint: TypeNode | undefined;
|
||||
constraint: JSDocTypeExpression | undefined;
|
||||
typeParameters: NodeArray<TypeParameterDeclaration>;
|
||||
}
|
||||
|
||||
@@ -5532,33 +5532,34 @@ namespace ts {
|
||||
BarDelimited = 1 << 2, // Each list item is space-and-bar (" |") delimited.
|
||||
AmpersandDelimited = 1 << 3, // Each list item is space-and-ampersand (" &") delimited.
|
||||
CommaDelimited = 1 << 4, // Each list item is comma (",") delimited.
|
||||
DelimitersMask = BarDelimited | AmpersandDelimited | CommaDelimited,
|
||||
AsteriskDelimited = 1 << 5, // Each list item is asterisk ("\n *") delimited, used with JSDoc.
|
||||
DelimitersMask = BarDelimited | AmpersandDelimited | CommaDelimited | AsteriskDelimited,
|
||||
|
||||
AllowTrailingComma = 1 << 5, // Write a trailing comma (",") if present.
|
||||
AllowTrailingComma = 1 << 6, // Write a trailing comma (",") if present.
|
||||
|
||||
// Whitespace
|
||||
Indented = 1 << 6, // The list should be indented.
|
||||
SpaceBetweenBraces = 1 << 7, // Inserts a space after the opening brace and before the closing brace.
|
||||
SpaceBetweenSiblings = 1 << 8, // Inserts a space between each sibling node.
|
||||
Indented = 1 << 7, // The list should be indented.
|
||||
SpaceBetweenBraces = 1 << 8, // Inserts a space after the opening brace and before the closing brace.
|
||||
SpaceBetweenSiblings = 1 << 9, // Inserts a space between each sibling node.
|
||||
|
||||
// Brackets/Braces
|
||||
Braces = 1 << 9, // The list is surrounded by "{" and "}".
|
||||
Parenthesis = 1 << 10, // The list is surrounded by "(" and ")".
|
||||
AngleBrackets = 1 << 11, // The list is surrounded by "<" and ">".
|
||||
SquareBrackets = 1 << 12, // The list is surrounded by "[" and "]".
|
||||
Braces = 1 << 10, // The list is surrounded by "{" and "}".
|
||||
Parenthesis = 1 << 11, // The list is surrounded by "(" and ")".
|
||||
AngleBrackets = 1 << 12, // The list is surrounded by "<" and ">".
|
||||
SquareBrackets = 1 << 13, // The list is surrounded by "[" and "]".
|
||||
BracketsMask = Braces | Parenthesis | AngleBrackets | SquareBrackets,
|
||||
|
||||
OptionalIfUndefined = 1 << 13, // Do not emit brackets if the list is undefined.
|
||||
OptionalIfEmpty = 1 << 14, // Do not emit brackets if the list is empty.
|
||||
OptionalIfUndefined = 1 << 14, // Do not emit brackets if the list is undefined.
|
||||
OptionalIfEmpty = 1 << 15, // Do not emit brackets if the list is empty.
|
||||
Optional = OptionalIfUndefined | OptionalIfEmpty,
|
||||
|
||||
// Other
|
||||
PreferNewLine = 1 << 15, // Prefer adding a LineTerminator between synthesized nodes.
|
||||
NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list.
|
||||
NoInterveningComments = 1 << 17, // Do not emit comments between each node
|
||||
PreferNewLine = 1 << 16, // Prefer adding a LineTerminator between synthesized nodes.
|
||||
NoTrailingNewLine = 1 << 17, // Do not emit a trailing NewLine for a MultiLine list.
|
||||
NoInterveningComments = 1 << 18, // Do not emit comments between each node
|
||||
|
||||
NoSpaceIfEmpty = 1 << 18, // If the literal is empty, do not add spaces between braces.
|
||||
SingleElement = 1 << 19,
|
||||
NoSpaceIfEmpty = 1 << 19, // If the literal is empty, do not add spaces between braces.
|
||||
SingleElement = 1 << 20,
|
||||
|
||||
// Precomputed Formats
|
||||
Modifiers = SingleLine | SpaceBetweenSiblings | NoInterveningComments,
|
||||
@@ -5598,6 +5599,7 @@ namespace ts {
|
||||
TypeParameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | AngleBrackets | Optional,
|
||||
Parameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis,
|
||||
IndexSignatureParameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | SquareBrackets,
|
||||
JSDocComment = MultiLine | AsteriskDelimited,
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
Reference in New Issue
Block a user