mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00: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:
+13
-48
@@ -209,12 +209,6 @@ namespace ts.textChanges {
|
||||
|
||||
export type TypeAnnotatable = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature;
|
||||
|
||||
interface JSDocParameter {
|
||||
declaration: ParameterDeclaration;
|
||||
typeNode: TypeNode;
|
||||
isOptional?: boolean;
|
||||
}
|
||||
|
||||
export class ChangeTracker {
|
||||
private readonly changes: Change[] = [];
|
||||
private readonly newFiles: { readonly oldFile: SourceFile | undefined, readonly fileName: string, readonly statements: ReadonlyArray<Statement> }[] = [];
|
||||
@@ -345,10 +339,19 @@ namespace ts.textChanges {
|
||||
this.insertText(sourceFile, token.getStart(sourceFile), text);
|
||||
}
|
||||
|
||||
public insertCommentThenNewline(sourceFile: SourceFile, character: number, position: number, commentText: string): void {
|
||||
const token = getTouchingToken(sourceFile, position);
|
||||
const text = "/**" + commentText + "*/" + this.newLineCharacter + repeatString(" ", character);
|
||||
this.insertText(sourceFile, token.getStart(sourceFile), text);
|
||||
public insertJsdocCommentBefore(sourceFile: SourceFile, node: HasJSDoc, tag: JSDoc) {
|
||||
const fnStart = node.getStart(sourceFile);
|
||||
if (node.jsDoc) {
|
||||
for (const jsdoc of node.jsDoc) {
|
||||
this.deleteRange(sourceFile, {
|
||||
pos: getLineStartPositionForPosition(jsdoc.getStart(sourceFile), sourceFile),
|
||||
end: getAdjustedEndPosition(sourceFile, jsdoc, /*options*/ {})
|
||||
});
|
||||
}
|
||||
}
|
||||
const startPosition = getPrecedingNonSpaceCharacterPosition(sourceFile.text, fnStart - 1);
|
||||
const indent = sourceFile.text.slice(startPosition, fnStart);
|
||||
this.insertNodeAt(sourceFile, fnStart, tag, { preserveLeadingWhitespace: false, suffix: this.newLineCharacter + indent });
|
||||
}
|
||||
|
||||
public replaceRangeWithText(sourceFile: SourceFile, range: TextRange, text: string) {
|
||||
@@ -359,23 +362,6 @@ namespace ts.textChanges {
|
||||
this.replaceRangeWithText(sourceFile, createRange(pos), text);
|
||||
}
|
||||
|
||||
public tryInsertJSDocParameters(sourceFile: SourceFile, parameters: JSDocParameter[]) {
|
||||
if (parameters.length === 0) {
|
||||
return;
|
||||
}
|
||||
const parent = parameters[0].declaration.parent;
|
||||
const indent = getLineAndCharacterOfPosition(sourceFile, parent.getStart()).character;
|
||||
let commentText = "\n";
|
||||
for (const { declaration, typeNode, isOptional } of parameters) {
|
||||
if (isIdentifier(declaration.name)) {
|
||||
const printed = changesToText.getNonformattedText(typeNode, sourceFile, this.newLineCharacter).text;
|
||||
commentText += this.printJSDocParameter(indent, printed, declaration.name, isOptional);
|
||||
}
|
||||
}
|
||||
commentText += repeatString(" ", indent + 1);
|
||||
this.insertCommentThenNewline(sourceFile, indent, parent.getStart(), commentText);
|
||||
}
|
||||
|
||||
/** Prefer this over replacing a node with another that has a type annotation, as it avoids reformatting the other parts of the node. */
|
||||
public tryInsertTypeAnnotation(sourceFile: SourceFile, node: TypeAnnotatable, type: TypeNode): void {
|
||||
let endNode: Node | undefined;
|
||||
@@ -394,27 +380,6 @@ namespace ts.textChanges {
|
||||
this.insertNodeAt(sourceFile, endNode.end, type, { prefix: ": " });
|
||||
}
|
||||
|
||||
public tryInsertJSDocType(sourceFile: SourceFile, node: Node, type: TypeNode): void {
|
||||
const printed = changesToText.getNonformattedText(type, sourceFile, this.newLineCharacter).text;
|
||||
let commentText;
|
||||
if (isGetAccessorDeclaration(node)) {
|
||||
commentText = ` @return {${printed}} `;
|
||||
}
|
||||
else {
|
||||
commentText = ` @type {${printed}} `;
|
||||
node = node.parent;
|
||||
}
|
||||
this.insertCommentThenNewline(sourceFile, getLineAndCharacterOfPosition(sourceFile, node.getStart(sourceFile)).character, node.getStart(sourceFile), commentText);
|
||||
}
|
||||
|
||||
private printJSDocParameter(indent: number, printed: string, name: Identifier, isOptionalParameter: boolean | undefined) {
|
||||
let printName = unescapeLeadingUnderscores(name.escapedText);
|
||||
if (isOptionalParameter) {
|
||||
printName = `[${printName}]`;
|
||||
}
|
||||
return repeatString(" ", indent) + ` * @param {${printed}} ${printName}\n`;
|
||||
}
|
||||
|
||||
public insertTypeParameters(sourceFile: SourceFile, node: SignatureDeclaration, typeParameters: ReadonlyArray<TypeParameterDeclaration>): void {
|
||||
// If no `(`, is an arrow function `x => x`, so use the pos of the first parameter
|
||||
const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)).getStart(sourceFile);
|
||||
|
||||
Reference in New Issue
Block a user