diff --git a/.README/rules/check-line-alignment.md b/.README/rules/check-line-alignment.md index 1ae10ba4b..87a807e8a 100644 --- a/.README/rules/check-line-alignment.md +++ b/.README/rules/check-line-alignment.md @@ -22,10 +22,21 @@ Use this to change the tags which are sought for alignment changes. *Currently* *only works with the "never" option.* Defaults to an array of `['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return']`. +##### `customSpacings` + +An object with any of the following keys set to an integer. Affects spacing: + +- `postDelimiter` - after the asterisk (e.g., `* @param`) +- `postTag` - after the tag (e.g., `* @param `) +- `postType` - after the type (e.g., `* @param {someType} `) +- `postName` - after the name (e.g., `* @param {someType} name `) + +If a spacing is not defined, it defaults to one. + ||| |---|---| |Context|everywhere| -|Options|(a string matching `"always" or "never"` and optional object with `tags`)| +|Options|(a string matching `"always" or "never"` and optional object with `tags` and `customSpacings`)| |Tags|`param`, `property`, `returns` and others added by `tags`| |Aliases|`arg`, `argument`, `prop`, `return`| |Recommended|false| diff --git a/README.md b/README.md index 789da96f7..c7a3026f5 100644 --- a/README.md +++ b/README.md @@ -1944,10 +1944,22 @@ Use this to change the tags which are sought for alignment changes. *Currently* *only works with the "never" option.* Defaults to an array of `['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return']`. + +##### customSpacings + +An object with any of the following keys set to an integer. Affects spacing: + +- `postDelimiter` - after the asterisk (e.g., `* @param`) +- `postTag` - after the tag (e.g., `* @param `) +- `postType` - after the type (e.g., `* @param {someType} `) +- `postName` - after the name (e.g., `* @param {someType} name `) + +If a spacing is not defined, it defaults to one. + ||| |---|---| |Context|everywhere| -|Options|(a string matching `"always" or "never"` and optional object with `tags`)| +|Options|(a string matching `"always" or "never"` and optional object with `tags` and `customSpacings`)| |Tags|`param`, `property`, `returns` and others added by `tags`| |Aliases|`arg`, `argument`, `prop`, `return`| |Recommended|false| @@ -2264,6 +2276,50 @@ function quux () {} const fn = ( lorem, sit ) => {} // "jsdoc/check-line-alignment": ["error"|"warn", "always"] // Message: Expected JSDoc block lines to be aligned. + +/** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ +const fn = ( lorem, sit ) => {} +// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"customSpacings":{"postDelimiter":2,"postTag":3,"postType":2}}] +// Message: Expected JSDoc block lines to be aligned. + +/** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ +const fn = ( lorem, sit ) => {} +// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"customSpacings":{"postName":3}}] +// Message: Expected JSDoc block lines to be aligned. + +/** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ +const fn = ( lorem, sit ) => {} +// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"customSpacings":{"postDelimiter":2,"postTag":3,"postType":2}}] +// Message: Expected JSDoc block lines to not be aligned. + +/** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ +const fn = ( lorem, sit ) => {} +// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"customSpacings":{"postName":3}}] +// Message: Expected JSDoc block lines to not be aligned. ```` The following patterns are not considered problems: @@ -2489,6 +2545,28 @@ function func(parameter){ */ const fn = ( lorem, sit ) => {} // "jsdoc/check-line-alignment": ["error"|"warn", "always",{"preserveMainDescriptionPostDelimiter":true}] + +/** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ +const fn = ( lorem, sit ) => {} +// "jsdoc/check-line-alignment": ["error"|"warn", "always",{"customSpacings":{"postDelimiter":2,"postTag":3,"postType":2}}] + +/** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ +const fn = ( lorem, sit ) => {} +// "jsdoc/check-line-alignment": ["error"|"warn", "never",{"customSpacings":{"postDelimiter":2,"postTag":3,"postType":2}}] ```` diff --git a/src/alignTransform.js b/src/alignTransform.js index 8caf2e033..85962cdce 100644 --- a/src/alignTransform.js +++ b/src/alignTransform.js @@ -1,3 +1,9 @@ +/** + * Transform based on https://github.com/syavorsky/comment-parser/blob/master/src/transforms/align.ts + * + * It contains some customizations to align based on the tags, and some custom options. + */ + import { Markers, } from 'comment-parser/lib/primitives'; @@ -58,7 +64,12 @@ const space = (len) => { return ''.padStart(len, ' '); }; -const alignTransform = (tags, indent, preserveMainDescriptionPostDelimiter) => { +const alignTransform = ({ + customSpacings, + tags, + indent, + preserveMainDescriptionPostDelimiter, +}) => { let intoTags = false; let width; @@ -90,17 +101,24 @@ const alignTransform = (tags, indent, preserveMainDescriptionPostDelimiter) => { } } - tokens.postDelimiter = nothingAfter.delim ? '' : ' '; + const spacings = { + postDelimiter: customSpacings?.postDelimiter || 1, + postName: customSpacings?.postName || 1, + postTag: customSpacings?.postTag || 1, + postType: customSpacings?.postType || 1, + }; + + tokens.postDelimiter = nothingAfter.delim ? '' : space(spacings.postDelimiter); if (!nothingAfter.tag) { - tokens.postTag = space(width.tag - tokens.tag.length + 1); + tokens.postTag = space(width.tag - tokens.tag.length + spacings.postTag); } if (!nothingAfter.type) { - tokens.postType = space(width.type - tokens.type.length + 1); + tokens.postType = space(width.type - tokens.type.length + spacings.postType); } if (!nothingAfter.name) { // If post name is empty for all lines (name width 0), don't add post name spacing. - tokens.postName = width.name === 0 ? '' : space(width.name - tokens.name.length + 1); + tokens.postName = width.name === 0 ? '' : space(width.name - tokens.name.length + spacings.postName); } return tokens; diff --git a/src/rules/checkLineAlignment.js b/src/rules/checkLineAlignment.js index 910ea525e..d7fccce22 100644 --- a/src/rules/checkLineAlignment.js +++ b/src/rules/checkLineAlignment.js @@ -8,7 +8,7 @@ const { flow: commentFlow, } = transforms; -const checkNotAlignedPerTag = (utils, tag) => { +const checkNotAlignedPerTag = (utils, tag, customSpacings) => { /* start + delimiter + @@ -61,11 +61,12 @@ const checkNotAlignedPerTag = (utils, tag) => { const contentProp = contentProps[idx]; const contentPropVal = tokens[contentProp]; const spacerPropVal = tokens[spacerProp]; + const spacing = customSpacings?.[spacerProp] || 1; // There will be extra alignment if... - // 1. There is extra whitespace within a single spacer segment OR - return spacerPropVal.length > 1 || + // 1. The spaces don't match the space it should have (1 or custom spacing) OR + return spacerPropVal.length !== spacing && spacerPropVal.length !== 0 || // 2. There is a (single) space, no immediate content, and yet another // space is found subsequently (not separated by intervening content) @@ -80,7 +81,8 @@ const checkNotAlignedPerTag = (utils, tag) => { const contentPropVal = tokens[contentProp]; if (contentPropVal) { - tokens[spacerProp] = ' '; + const spacing = customSpacings?.[spacerProp] || 1; + tokens[spacerProp] = ''.padStart(spacing, ' '); followedBySpace(idx, (hasSpace, contentPrp) => { if (hasSpace) { tokens[contentPrp] = ''; @@ -97,6 +99,7 @@ const checkNotAlignedPerTag = (utils, tag) => { }; const checkAlignment = ({ + customSpacings, indent, jsdoc, jsdocNode, @@ -105,7 +108,14 @@ const checkAlignment = ({ tags, utils, }) => { - const transform = commentFlow(alignTransform(tags, indent, preserveMainDescriptionPostDelimiter)); + const transform = commentFlow( + alignTransform({ + customSpacings, + indent, + preserveMainDescriptionPostDelimiter, + tags, + }), + ); const transformedJsdoc = transform(jsdoc); const comment = '/*' + jsdocNode.value + '*/'; @@ -133,6 +143,7 @@ export default iterateJsdoc(({ const { tags: applicableTags = ['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return'], preserveMainDescriptionPostDelimiter, + customSpacings, } = context.options[1] || {}; if (context.options[0] === 'always') { @@ -142,6 +153,7 @@ export default iterateJsdoc(({ } checkAlignment({ + customSpacings, indent, jsdoc, jsdocNode, @@ -156,7 +168,7 @@ export default iterateJsdoc(({ const foundTags = utils.getPresentTags(applicableTags); foundTags.forEach((tag) => { - checkNotAlignedPerTag(utils, tag); + checkNotAlignedPerTag(utils, tag, customSpacings); }); }, { iterateAllJsdocs: true, @@ -174,6 +186,23 @@ export default iterateJsdoc(({ { additionalProperties: false, properties: { + customSpacings: { + additionalProperties: false, + properties: { + postDelimiter: { + type: 'integer', + }, + postName: { + type: 'integer', + }, + postTag: { + type: 'integer', + }, + postType: { + type: 'integer', + }, + }, + }, preserveMainDescriptionPostDelimiter: { default: false, type: 'boolean', diff --git a/test/rules/assertions/checkLineAlignment.js b/test/rules/assertions/checkLineAlignment.js index 5849aa6b1..438d6f745 100644 --- a/test/rules/assertions/checkLineAlignment.js +++ b/test/rules/assertions/checkLineAlignment.js @@ -917,6 +917,146 @@ export default { const fn = ( lorem, sit ) => {} `, }, + { + code: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ + const fn = ( lorem, sit ) => {} + `, + errors: [ + { + line: 2, + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + options: ['always', { + customSpacings: { + postDelimiter: 2, + postTag: 3, + postType: 2, + }, + }], + output: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ + const fn = ( lorem, sit ) => {} + `, + }, + { + code: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ + const fn = ( lorem, sit ) => {} + `, + errors: [ + { + line: 2, + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + options: ['always', { + customSpacings: { + postName: 3, + }, + }], + output: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ + const fn = ( lorem, sit ) => {} + `, + }, + { + code: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + errors: [ + { + line: 6, + message: 'Expected JSDoc block lines to not be aligned.', + type: 'Block', + }, + ], + options: ['never', { + customSpacings: { + postDelimiter: 2, + postTag: 3, + postType: 2, + }, + }], + output: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + }, + { + code: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + errors: [ + { + line: 6, + message: 'Expected JSDoc block lines to not be aligned.', + type: 'Block', + }, + ], + options: ['never', { + customSpacings: { + postName: 3, + }, + }], + output: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + }, ], valid: [ { @@ -1255,5 +1395,45 @@ export default { preserveMainDescriptionPostDelimiter: true, }], }, + { + code: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ + const fn = ( lorem, sit ) => {} + `, + options: ['always', { + customSpacings: { + postDelimiter: 2, + postTag: 3, + postType: 2, + }, + }], + }, + { + code: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + * + * @return {string} Return description. + */ + const fn = ( lorem, sit ) => {} + `, + options: ['never', { + customSpacings: { + postDelimiter: 2, + postTag: 3, + postType: 2, + }, + }], + }, ], };