Skip to content

Commit

Permalink
feat(prettier-plugin-jsdoc): add function to render tag in columns
Browse files Browse the repository at this point in the history
  • Loading branch information
homer0 committed Oct 6, 2020
1 parent 51724b0 commit 6db0bf0
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 0 deletions.
63 changes: 63 additions & 0 deletions src/fns/renderTagInColumns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const R = require('ramda');
const { splitText } = require('./splitText');

/**
* @typedef {import('../types').CommentTag} CommentTag
*/

/**
* 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
* be splitted in multiple lines, with padding for the other columns on each new line.
*
* @callback RenderTagInColumnsFn
* @param {number} tagColumnWidth The width of the column for the tag, including the
* `@` symbol.
* @param {number} typeColumnWidth The width of the column for the type, it will only
* be used if the tag has a `type` property.
* @param {number} nameColumnWidth The width of the column for the name, it will only
* be used if the tag has a `name` property.
* @param {number} descriptionColumnWidth The width of the column for th description.
* @param {CommentTag} tag The tag to render.
* @returns {string[]}
*/

/**
* @type {RenderTagInColumnsFn}
*/
const renderTagInColumns = R.curry((
tagColumnWidth,
typeColumnWidth,
nameColumnWidth,
descriptionColumnWidth,
tag,
) => {
const descriptionLines = tag.description ?
splitText(tag.description, descriptionColumnWidth) :
[''];

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

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

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

firstLineParts.push(descriptionLines.shift());
const firstLine = firstLineParts.join('').trim();
const descriptionPadding = ' '.repeat(descriptionPaddingWidth);
return [
firstLine,
...descriptionLines.map((line) => `${descriptionPadding}${line}`),
];
});

module.exports.renderTagInColumns = renderTagInColumns;
122 changes: 122 additions & 0 deletions test/fns/renderTagInColumns.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
jest.unmock('../../src/fns/renderTagInColumns');
jest.unmock('../../src/fns/utils');
jest.unmock('../../src/fns/splitText');

const { renderTagInColumns } = require('../../src/fns/renderTagInColumns');

describe('renderTagInColumns', () => {
const cases = [
{
it: 'should render a tag with a type and a description',
input: {
tag: 'param',
type: 'string',
name: 'myParam',
description: [
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas',
'sollicitudin non justo quis placerat. Quisque eu dignissim tellus, ut',
'sodales lectus.',
].join(' '),
},
output: [
'@param {string} myParam Lorem ipsum dolor sit amet,',
' consectetur adipiscing',
' elit. Maecenas sollicitudin',
' non justo quis placerat.',
' Quisque eu dignissim',
' tellus, ut sodales lectus.',
],
options: {
tagColumnWidth: 10,
typeColumnWidth: 10,
nameColumnWidth: 14,
descriptionColumnWidth: 27,
},
},
{
it: 'should render a tag without a description',
input: {
tag: 'param',
type: 'string',
name: 'myParam',
description: '',
},
output: [
'@param {string} myParam',
],
options: {
tagColumnWidth: 10,
typeColumnWidth: 10,
nameColumnWidth: 14,
descriptionColumnWidth: 27,
},
},
{
it: 'should render a tag without a type and a name',
input: {
tag: 'description',
type: '',
name: '',
description: [
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas',
'sollicitudin non justo quis placerat. Quisque eu dignissim tellus, ut',
'sodales lectus.',
].join(' '),
},
output: [
'@description Lorem ipsum dolor sit amet, consectetur adipiscing',
' elit. Maecenas sollicitudin non justo quis',
' placerat. Quisque eu dignissim tellus, ut sodales',
' lectus.',
],
options: {
tagColumnWidth: 13,
typeColumnWidth: 0,
nameColumnWidth: 0,
descriptionColumnWidth: 50,
},
},
{
it: 'should render a tag without a name',
input: {
tag: 'throws',
type: 'Error',
name: '',
description: [
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas',
'sollicitudin non justo quis placerat. Quisque eu dignissim tellus, ut',
'sodales lectus.',
].join(' '),
},
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: 14,
descriptionColumnWidth: 27,
},
},
];

it.each(cases)('should correctly format the case %#', (caseInfo) => {
// Given
let result = null;
// When
result = renderTagInColumns(
caseInfo.options.tagColumnWidth,
caseInfo.options.typeColumnWidth,
caseInfo.options.nameColumnWidth,
caseInfo.options.descriptionColumnWidth,
caseInfo.input,
);
// Then
expect(result).toEqual(caseInfo.output);
});
});

0 comments on commit 6db0bf0

Please sign in to comment.