Skip to content

Commit

Permalink
Support nestled JSDoc comments (prettier#13445)
Browse files Browse the repository at this point in the history
  • Loading branch information
thorn0 authored and medikoo committed Feb 1, 2024
1 parent ba49d38 commit f788253
Show file tree
Hide file tree
Showing 8 changed files with 341 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ module.exports = {
},
{
files: ["src/language-js/**/*.js"],
excludedFiles: ["src/language-js/parse/postprocess/*.js"],
rules: {
"prettier-internal-rules/no-node-comments": [
"error",
Expand All @@ -330,7 +331,6 @@ module.exports = {
functions: ["hasComment", "getComments"],
},
"src/language-js/pragma.js",
"src/language-js/parse/postprocess/*.js",
"src/language-js/parse/babel.js",
"src/language-js/parse/meriyah.js",
"src/language-js/parse/json.js",
Expand Down
60 changes: 60 additions & 0 deletions changelog_unreleased/javascript/13445.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#### Support nestled JSDoc comments (#13445 by @thorn0)

This kind of comments is used to document overloaded functions (see https://github.com/jsdoc/jsdoc/issues/1017).

<!-- prettier-ignore -->
```jsx
// Input
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*//**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}

// Prettier stable
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*/ /**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}

// Prettier main
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*//**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}
```
22 changes: 22 additions & 0 deletions src/language-js/parse/postprocess/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { locStart, locEnd } from "../../loc.js";
import isTsKeywordType from "../../utils/is-ts-keyword-type.js";
import isTypeCastComment from "../../utils/is-type-cast-comment.js";
import getLast from "../../../utils/get-last.js";
import isNonEmptyArray from "../../../utils/is-non-empty-array.js";
import isBlockComment from "../../utils/is-block-comment.js";
import isIndentableBlockComment from "../../utils/is-indentable-block-comment.js";
import visitNode from "./visit-node.js";
import throwSyntaxError from "./throw-ts-syntax-error.js";

Expand Down Expand Up @@ -165,6 +168,25 @@ function postprocess(ast, options) {
}
});

if (isNonEmptyArray(ast.comments)) {
let followingComment = getLast(ast.comments);
for (let i = ast.comments.length - 2; i >= 0; i--) {
const comment = ast.comments[i];
if (
locEnd(comment) === locStart(followingComment) &&
isBlockComment(comment) &&
isBlockComment(followingComment) &&
isIndentableBlockComment(comment) &&
isIndentableBlockComment(followingComment)
) {
ast.comments.splice(i + 1, 1);
comment.value += "*//*" + followingComment.value;
comment.range = [locStart(comment), locEnd(followingComment)];
}
followingComment = comment;
}
}

return ast;

/**
Expand Down
12 changes: 2 additions & 10 deletions src/language-js/print/comment.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { replaceEndOfLine } from "../../document/utils.js";
import { isLineComment } from "../utils/index.js";
import { locStart, locEnd } from "../loc.js";
import isBlockComment from "../utils/is-block-comment.js";
import isIndentableBlockComment from "../utils/is-indentable-block-comment.js";

function printComment(commentPath, options) {
const comment = commentPath.node;
Expand Down Expand Up @@ -34,15 +35,6 @@ function printComment(commentPath, options) {
throw new Error("Not a comment: " + JSON.stringify(comment));
}

function isIndentableBlockComment(comment) {
// If the comment has multiple lines and every line starts with a star
// we can fix the indentation of each line. The stars in the `/*` and
// `*/` delimiters are not included in the comment value, so add them
// back first.
const lines = `*${comment.value}*`.split("\n");
return lines.length > 1 && lines.every((line) => line.trim()[0] === "*");
}

function printIndentableBlockComment(comment) {
const lines = comment.value.split("\n");

Expand All @@ -60,4 +52,4 @@ function printIndentableBlockComment(comment) {
];
}

export { printComment };
export { printComment, isIndentableBlockComment };
10 changes: 10 additions & 0 deletions src/language-js/utils/is-indentable-block-comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function isIndentableBlockComment(comment) {
// If the comment has multiple lines and every line starts with a star
// we can fix the indentation of each line. The stars in the `/*` and
// `*/` delimiters are not included in the comment value, so add them
// back first.
const lines = `*${comment.value}*`.split("\n");
return lines.length > 1 && lines.every((line) => line.trimStart()[0] === "*");
}

export default isIndentableBlockComment;
224 changes: 224 additions & 0 deletions tests/format/js/comments/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3134,6 +3134,230 @@ function HelloWorld() {
================================================================================
`;
exports[`jsdoc-nestled.js - {"semi":false} format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
semi: false
| printWidth
=====================================input======================================
const issues = {
see: "#7724 and #12653"
/** Trailing comment 1 (not nestled as both comments should be multiline for that) *//**
* Trailing comment 2
*/
};
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*//**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}
/** Trailing nestled comment 1
*//** Trailing nestled comment 2
*//** Trailing nestled comment 3
*/
=====================================output=====================================
const issues = {
see: "#7724 and #12653",
/** Trailing comment 1 (not nestled as both comments should be multiline for that) */ /**
* Trailing comment 2
*/
}
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*//**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value)
} else {
return new Value(type)
}
}
/** Trailing nestled comment 1
*//** Trailing nestled comment 2
*//** Trailing nestled comment 3
*/
================================================================================
`;
exports[`jsdoc-nestled.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
| printWidth
=====================================input======================================
const issues = {
see: "#7724 and #12653"
/** Trailing comment 1 (not nestled as both comments should be multiline for that) *//**
* Trailing comment 2
*/
};
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*//**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}
/** Trailing nestled comment 1
*//** Trailing nestled comment 2
*//** Trailing nestled comment 3
*/
=====================================output=====================================
const issues = {
see: "#7724 and #12653",
/** Trailing comment 1 (not nestled as both comments should be multiline for that) */ /**
* Trailing comment 2
*/
};
/**
* @template T
* @param {Type} type
* @param {T} value
* @return {Value}
*//**
* @param {Type} type
* @return {Value}
*/
function value(type, value) {
if (arguments.length === 2) {
return new ConcreteValue(type, value);
} else {
return new Value(type);
}
}
/** Trailing nestled comment 1
*//** Trailing nestled comment 2
*//** Trailing nestled comment 3
*/
================================================================================
`;
exports[`jsdoc-nestled-dangling.js - {"semi":false} format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
semi: false
| printWidth
=====================================input======================================
{{{{{{{
o={
/**
* A
*//**
* B
*/
}
}}}}}}}
=====================================output=====================================
{
{
{
{
{
{
{
o = {
/**
* A
*//**
* B
*/
}
}
}
}
}
}
}
}
================================================================================
`;
exports[`jsdoc-nestled-dangling.js format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
printWidth: 80
| printWidth
=====================================input======================================
{{{{{{{
o={
/**
* A
*//**
* B
*/
}
}}}}}}}
=====================================output=====================================
{
{
{
{
{
{
{
o = {
/**
* A
*//**
* B
*/
};
}
}
}
}
}
}
}
================================================================================
`;
exports[`jsx.js - {"semi":false} format 1`] = `
====================================options=====================================
parsers: ["babel", "flow", "typescript"]
Expand Down
10 changes: 10 additions & 0 deletions tests/format/js/comments/jsdoc-nestled-dangling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{{{{{{{
o={
/**
* A
*//**
* B
*/

}
}}}}}}}

0 comments on commit f788253

Please sign in to comment.