Skip to content

Commit

Permalink
feat(prettier-plugin-jsdoc): add function that fixes descriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
homer0 committed Oct 24, 2020
1 parent f5747fb commit 41952ab
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 31 deletions.
40 changes: 40 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,44 @@ const TAGS_SYNONYMS = {
examples: 'example',
};

const TAGS_WITH_TYPE_AS_NAME = [
'aguments',
'extends',
'constructs',
'event',
'external',
'fires',
'interface',
'lends',
'listens',
'memberof',
'memberof!',
'mixes',
'requires',
];

const TAGS_WITH_DESCRIPTION_AS_NAME = [
'author',
'classdesc',
'copyright',
'deprecated',
'description',
'desc',
'example',
'file',
'license',
'summary',
'throws',
'todo',
];

const TAGS_WITH_NAME_AS_DESCRIPTION = [
'see',
'borrows',
'yields',
];

module.exports.TAGS_SYNONYMS = TAGS_SYNONYMS;
module.exports.TAGS_WITH_TYPE_AS_NAME = TAGS_WITH_TYPE_AS_NAME;
module.exports.TAGS_WITH_DESCRIPTION_AS_NAME = TAGS_WITH_DESCRIPTION_AS_NAME;
module.exports.TAGS_WITH_NAME_AS_DESCRIPTION = TAGS_WITH_NAME_AS_DESCRIPTION;
2 changes: 2 additions & 0 deletions src/fns/formatTags.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const { formatAccessTag } = require('./formatAccessTag');
const { replaceTagsSynonyms } = require('./replaceTagsSynonyms');
const { sortTags } = require('./sortTags');
const { trimTagsProperties } = require('./trimTagsProperties');
const { formatTagsDescription } = require('./formatTagsDescription');

/**
* @typedef {import('../types').CommentTag} CommentTag
Expand All @@ -23,6 +24,7 @@ const { trimTagsProperties } = require('./trimTagsProperties');
*/
const formatTags = R.curry((tags, options) => {
const fns = [
formatTagsDescription,
trimTagsProperties,
formatAccessTag(R.__, options),
];
Expand Down
110 changes: 110 additions & 0 deletions src/fns/formatTagsDescription.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
const R = require('ramda');
const {
TAGS_WITH_DESCRIPTION_AS_NAME,
TAGS_WITH_NAME_AS_DESCRIPTION,
} = require('../constants');
const { isTag, hasValidProperty } = require('./utils');

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

/**
* Checks if a tag description starts with a new line or not in order to add the
* `descriptionParagrah` flag property.
*
* @param {CommentTag} tag The tag where the flag will be added.
* @returns {CommentTag}
*/
const addParagraphFlag = (tag) => ({
...tag,
descriptionParagrah: tag.description.startsWith('\n'),
});

/**
* Utility function that fixes texts from properties that were splitted incorrectly. For example,
* the parser would take the text from a `description` text, set the first word as the tag `name`
* and the rest as `description`.
*
* @callback JoinPropertiesFn
* @param {string} propA The property that starts the text.
* @param {string} propB The property that ends the text.
* @param {string} prop The property where the text will be placed. This needs to be the
* value of either `propA` or `propB`, and whichever you don't choose
* will be left as an empty string.
* @param {CommentTag} tag The tag to format.
* @returns {CommentTag}
*/

/**
* @type {JoinPropertiesFn}
*/
const joinProperties = R.curry((propA, propB, prop, tag) => {
const cleanProp = prop === propA ? propB : propA;
const valA = tag[propA];
const valB = tag[propB];
let newVal;
if (valA.length && valB.length) {
newVal = `${tag[propA]} ${tag[propB]}`;
} else if (valB.length) {
newVal = valB;
} else {
newVal = valA;
}
return {
...tag,
[prop]: newVal,
[cleanProp]: '',
};
});

/**
* Takes a tag that has a link tag as a type and moves it to the property where the description
* starts.
*
* @param {CommentTag} tag The tag to fix.
* @returns {CommentTag}
*/
const addLinkToDescription = (tag) => {
const prop = TAGS_WITH_NAME_AS_DESCRIPTION.includes(tag.tag) ? 'description' : 'name';
return {
...tag,
type: '',
[prop]: `{${tag.type}} ${tag[prop]}`.trimRight(),
};
};

/**
* Formats the descriptions of a list of tags in order to fix those texts the parser may have
* incorrectly splitted (like the tag description that ends on `name` and `description`), moves
* `link` tags mistaken as types to the description, and then it adds the `descriptionParagrah`
* flag to the tags.
*
* @callback FormatTagsDescriptionFn
* @param {CommentTag[]} tags The list of tags to format.
* @returns {CommentTag[]}
*/

/**
* @type {FormatTagsDescriptionFn}
*/
const formatTagsDescription = R.map(R.compose(
addParagraphFlag,
R.when(
isTag(TAGS_WITH_NAME_AS_DESCRIPTION),
joinProperties('name', 'description', 'name'),
),
R.when(
isTag(TAGS_WITH_DESCRIPTION_AS_NAME),
joinProperties('name', 'description', 'description'),
),
R.when(
R.allPass([
hasValidProperty('type'),
R.propSatisfies(R.startsWith('@link'), 'type'),
]),
addLinkToDescription,
),
));

module.exports.formatTagsDescription = formatTagsDescription;
3 changes: 2 additions & 1 deletion src/fns/formatTagsTypes.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const R = require('ramda');
const { hasValidProperty } = require('./utils');
const { formatTSTypes } = require('./formatTSTypes');
const { formatStringLiterals } = require('./formatStringLiterals');
const { formatArrays } = require('./formatArrays');
Expand Down Expand Up @@ -82,7 +83,7 @@ const formatTagType = R.curry((formatter, tag) => R.compose(
* @type {FormatTagsTypes}
*/
const formatTagsTypes = R.curry((tags, options) => R.map(R.when(
R.propSatisfies(R.complement(R.either(R.isEmpty, R.isNil)), 'type'),
hasValidProperty('type'),
formatTagType(getTypeFormatter(options)),
))(tags));

Expand Down
18 changes: 18 additions & 0 deletions src/fns/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,23 @@ const limitAdjacentRepetitions = R.curry((pred, limit, list) => R.compose(
),
)(list));

/**
* Checks if an object was a specific property and is not _empty_.
*
* @callback HasValidPropertyFn
* @param {string} property The name of the property to validate.
* @param {Object} obj The object where the property will be validated.
* @returns {boolean}
*/

/**
* @type {HasValidPropertyFn}
*/
const hasValidProperty = R.curry((property, obj) => R.propSatisfies(
R.complement(R.either(R.isEmpty, R.isNil)),
property,
)(obj));

module.exports.ensureArray = ensureArray;
module.exports.findTagIndex = findTagIndex;
module.exports.isTag = isTag;
Expand All @@ -303,3 +320,4 @@ module.exports.replaceDotOnTypeGeneric = replaceDotOnTypeGeneric;
module.exports.capitalize = capitalize;
module.exports.getIndexOrFallback = getIndexOrFallback;
module.exports.limitAdjacentRepetitions = limitAdjacentRepetitions;
module.exports.hasValidProperty = hasValidProperty;
15 changes: 9 additions & 6 deletions src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,15 @@

/**
* @typedef {Object} CommentTag
* @property {string} tag The name of the tag.
* @property {string} type The type of what the tag represents, without the curly brackets.
* @property {string} name The name of what the tag represents.
* @property {string} description The description of what the tag represents.
* @property {boolean} optional Whether or not what the tag represents is optional.
* @property {string} [default] The default value of what the tag represents.
* @property {string} tag The name of the tag.
* @property {string} type The type of what the tag represents, without the curly
* brackets.
* @property {string} name The name of what the tag represents.
* @property {string} description The description of what the tag represents.
* @property {boolean} optional Whether or not what the tag represents is optional.
* @property {string} [default] The default value of what the tag represents.
* @property {boolean} [descriptionParagrah] If `true`, it means that the description was originally
* below the tag line.
*/

/**
Expand Down

0 comments on commit 41952ab

Please sign in to comment.