Skip to content

Commit

Permalink
feat(prettier-plugin-jsdoc): add support for multiline names
Browse files Browse the repository at this point in the history
  • Loading branch information
homer0 committed Oct 26, 2020
1 parent 9489967 commit 31563c6
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 11 deletions.
62 changes: 54 additions & 8 deletions src/fns/renderTagInColumns.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,44 @@ const { splitText } = require('./splitText');
* @typedef {import('../types').CommentTag} CommentTag
*/

/**
* When a tag has a multiline description and/or multiline name, this function will take care of
* rendering the rest of lines, respecting each property column space and add the necessary padding.
*
* @param {number} column The column where the lines should start.
* @param {boolean} hasName Whether or not there was a valid `name` property. Based on
* that, the function will decide if the space for the 'name
* column' should be padding or if it should be just removed.
* @param {number} nameColumnWidth The width of the column for the name.
* @param {string[]} nameLines The lines for the name.
* @param {string[]} descriptionLines The lines for the description.
* @returns {string[]}
*/
const renderRest = (
column,
hasName,
nameColumnWidth,
nameLines,
descriptionLines,
) => {
const result = [];
const limit = Math.max(nameLines.length, descriptionLines.length);
const padding = ' '.repeat(column);
const namePadding = hasName ? ' '.repeat(nameColumnWidth) : '';
for (let i = 0; i < limit; i++) {
const nameLine = nameLines[i] ?
nameLines[i].padEnd(nameColumnWidth) :
namePadding;
const descriptionLine = descriptionLines[i] ?
descriptionLines[i] :
'';

result.push(`${padding}${nameLine}${descriptionLine}`);
}

return result;
};

/**
* Renders a JSDoc tag using the `columns` style: there's a column for the tag, the type, the
* name and the description, and if the description is longer than the available space, it will
Expand Down Expand Up @@ -36,29 +74,37 @@ const renderTagInColumns = R.curry((
const descriptionLines = tag.description ?
splitText(tag.description, descriptionColumnWidth) :
[''];
const descriptionFirstLine = descriptionLines.shift();
let nameLines = [];

const firstLineParts = [
`@${tag.tag}`.padEnd(tagColumnWidth, ' '),
];

let descriptionPaddingWidth = tagColumnWidth;
let restColumn = tagColumnWidth;
if (tag.type) {
firstLineParts.push(`{${tag.type}}`.padEnd(typeColumnWidth));
descriptionPaddingWidth += typeColumnWidth;
restColumn += typeColumnWidth;
}

if (tag.name) {
firstLineParts.push(tag.name.padEnd(nameColumnWidth));
descriptionPaddingWidth += nameColumnWidth;
nameLines = splitText(tag.name, nameColumnWidth);
firstLineParts.push(nameLines.shift().padEnd(nameColumnWidth));
}

firstLineParts.push(descriptionLines.shift());
firstLineParts.push(descriptionFirstLine);
const firstLine = firstLineParts.join('').trim();
const descriptionPadding = ' '.repeat(descriptionPaddingWidth);
return [
firstLine,
...descriptionLines.map((line) => `${descriptionPadding}${line}`),
];
...renderRest(
restColumn,
!!tag.name,
nameColumnWidth,
nameLines,
descriptionLines,
),
]
.map((line) => line.trimEnd());
});

module.exports.renderTagInColumns = renderTagInColumns;
20 changes: 17 additions & 3 deletions src/fns/renderTagInLine.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const { splitText } = require('./splitText');

/**
* @type {RenderTagInLineFn}
* @todo Refactor how the multiline names are handled.
*/
const renderTagInLine = R.curry((width, typePadding, namePadding, tag) => {
const tagHeader = `@${tag.tag}`;
Expand All @@ -38,11 +39,24 @@ const renderTagInLine = R.curry((width, typePadding, namePadding, tag) => {
`${typeLastLine}}${useNamePadding}${tag.name}`,
];
} else {
const rest = `${useTypePadding}{${tag.type}}${useNamePadding}${tag.name}`.trimRight();
result = [`${tagHeader}${rest}`];
const tagHeaderWithSpace = `${tagHeader}${useTypePadding}{${tag.type}}${useNamePadding}`;
const nameWidth = width - tagHeaderWithSpace.length;
const nameLines = splitText(tag.name, nameWidth);
result = [`${tagHeaderWithSpace}${nameLines.shift()}`.trimRight()];
if (nameLines.length) {
const namePaddingForLine = ' '.repeat(tagHeaderWithSpace.length);
result.push(...nameLines.map((line) => `${namePaddingForLine}${line}`));
}
}
} else {
result = [`${tagHeader}${useNamePadding}${tag.name}`.trimRight()];
const tagHeaderWithSpace = `${tagHeader}${useNamePadding}`;
const nameWidth = width - tagHeaderWithSpace.length;
const nameLines = splitText(tag.name, nameWidth);
result = [`${tagHeaderWithSpace}${nameLines.shift()}`.trimRight()];
if (nameLines.length) {
const namePaddingForLine = ' '.repeat(tagHeaderWithSpace.length);
result.push(...nameLines.map((line) => `${namePaddingForLine}${line}`));
}
}

if (tag.description) {
Expand Down
27 changes: 27 additions & 0 deletions test/unit/fns/renderTagInColumns.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,33 @@ describe('renderTagInColumns', () => {
descriptionColumnWidth: 27,
},
},
{
it: 'should render a tag with a multiline name',
input: {
tag: 'throws',
type: 'Error',
name: [
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas',
'sollicitudin non justo quis placerat. Quisque eu dignissim tellus, ut',
'sodales lectus.',
].join(' '),
description: '',
},
output: [
'@throws {Error} Lorem ipsum dolor sit amet,',
' consectetur adipiscing',
' elit. Maecenas sollicitudin',
' non justo quis placerat.',
' Quisque eu dignissim',
' tellus, ut sodales lectus.',
],
options: {
tagColumnWidth: 8,
typeColumnWidth: 8,
nameColumnWidth: 27,
descriptionColumnWidth: 14,
},
},
];

it.each(cases)('should correctly format the case %#', (caseInfo) => {
Expand Down
51 changes: 51 additions & 0 deletions test/unit/fns/renderTagInLine.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,57 @@ describe('renderTagInLine', () => {
namePadding: 1,
},
},
{
it: 'should render a tag with a multiline name',
input: {
tag: 'throws',
type: 'Error',
name: [
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas',
'sollicitudin non justo quis placerat. Quisque eu dignissim tellus, ut',
'sodales lectus.',
].join(' '),
description: '',
},
output: [
'@throws {Error} Lorem ipsum dolor sit amet,',
' consectetur adipiscing elit.',
' Maecenas sollicitudin non justo',
' quis placerat. Quisque eu',
' dignissim tellus, ut sodales',
' lectus.',
],
options: {
width: 50,
typePadding: 1,
namePadding: 1,
},
},
{
it: 'should render a tag, without type, with a multiline name',
input: {
tag: 'see',
type: '',
name: [
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas',
'sollicitudin non justo quis placerat. Quisque eu dignissim tellus, ut',
'sodales lectus.',
].join(' '),
description: '',
},
output: [
'@see Lorem ipsum dolor sit amet,',
' consectetur adipiscing elit.',
' Maecenas sollicitudin non justo',
' quis placerat. Quisque eu dignissim',
' tellus, ut sodales lectus.',
],
options: {
width: 40,
typePadding: 1,
namePadding: 1,
},
},
];

it.each(cases)('should correctly format the case %#', (caseInfo) => {
Expand Down

0 comments on commit 31563c6

Please sign in to comment.