From e20942f7f5f3ee82640d1c4cd192b1f8c5e0eb94 Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Fri, 11 Sep 2020 15:06:25 -0300 Subject: [PATCH 01/12] Add check-lines-alignment rule --- src/index.js | 3 + src/rules/checkLinesAlignment.js | 209 +++++++++ test/rules/assertions/checkLinesAlignment.js | 461 +++++++++++++++++++ test/rules/index.js | 1 + 4 files changed, 674 insertions(+) create mode 100644 src/rules/checkLinesAlignment.js create mode 100644 test/rules/assertions/checkLinesAlignment.js diff --git a/src/index.js b/src/index.js index b9492dda1..e30642bac 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,7 @@ import checkAccess from './rules/checkAccess'; import checkAlignment from './rules/checkAlignment'; import checkExamples from './rules/checkExamples'; import checkIndentation from './rules/checkIndentation'; +import checkLinesAlignment from './rules/checkLinesAlignment'; import checkParamNames from './rules/checkParamNames'; import checkPropertyNames from './rules/checkPropertyNames'; import checkSyntax from './rules/checkSyntax'; @@ -47,6 +48,7 @@ export default { 'jsdoc/check-alignment': 'warn', 'jsdoc/check-examples': 'off', 'jsdoc/check-indentation': 'off', + 'jsdoc/check-lines-alignment': 'warn', 'jsdoc/check-param-names': 'warn', 'jsdoc/check-property-names': 'warn', 'jsdoc/check-syntax': 'off', @@ -88,6 +90,7 @@ export default { 'check-alignment': checkAlignment, 'check-examples': checkExamples, 'check-indentation': checkIndentation, + 'check-lines-alignment': checkLinesAlignment, 'check-param-names': checkParamNames, 'check-property-names': checkPropertyNames, 'check-syntax': checkSyntax, diff --git a/src/rules/checkLinesAlignment.js b/src/rules/checkLinesAlignment.js new file mode 100644 index 000000000..c4d1d75a6 --- /dev/null +++ b/src/rules/checkLinesAlignment.js @@ -0,0 +1,209 @@ +import { + set, +} from 'lodash'; +import iterateJsdoc from '../iterateJsdoc'; + +/** + * Create a sequence of chars with a specific size. + * + * @param {string} char The char. + * @param {int} length The length. + */ +const createSequence = (char, length) => { + return new Array(length + 1).join(char); +}; + +/** + * Aux method until we consider the dev envs support `String.prototype.matchAll` (Node 12+). + * + * @param {string} string String that will be checked. + * @param {RegExp} regexp Regular expression to run. + * @param {Function} callback Function to be called each iteration. + * @param {int} limit Limit of matches that we want to exec. + */ +const matchAll = (string, regexp, callback, limit) => { + let result; + let index = 0; + + while ((result = regexp.exec(string)) && index <= limit - 1) { + // eslint-disable-next-line promise/prefer-await-to-callbacks + callback(result, index++); + } +}; + +/** + * Get the full description from a line. + * + * @param {string} lineString The line string. + * + * @returns {string} The full description. + */ +const getFullDescription = (lineString) => { + return /(?:\S+\s+){4}(.*)/.exec(lineString)[1]; +}; + +/** + * Get the expected positions for each part. + * + * @param {Array[]} partsMatrix Parts matrix. + * @param {int[]} partsMaxLength Max length of each part. + * @param {int} indentLevel JSDoc indent level. + * + * @returns {int[]} Expected position for each part. + */ +const getExpectedPositions = (partsMatrix, partsMaxLength, indentLevel) => { + // eslint-disable-next-line unicorn/no-reduce + return partsMaxLength.reduce( + (acc, cur, index) => { + return [...acc, cur + acc[index] + 1]; + }, + [indentLevel], + ); +}; + +/** + * Check is not aligned. + * + * @param {int[]} expectedPositions Expected position for each part. + * @param {Array[]} partsMatrix Parts matrix. + * + * @returns {boolean} + */ +const isNotAligned = (expectedPositions, partsMatrix) => { + return partsMatrix.some((line) => { + return line.some( + ({position}, partIndex) => { + return position !== expectedPositions[partIndex]; + }, + ); + }); +}; + +/** + * Fix function creator for the report. It creates a function which fix + * the JSDoc with the correct alignment. + * + * @param {object} comment Comment node. + * @param {int[]} expectedPositions Array with the expected positions. + * @param {Array[]} partsMatrix Parts matrix. + * @param {RegExp} lineRegExp Line regular expression. + * @param {string} tagIndentation Tag indentation. + * + * @returns {Function} Function which fixes the JSDoc alignment. + */ +const createFixer = (comment, expectedPositions, partsMatrix, lineRegExp, tagIndentation) => { + return (fixer) => { + let lineIndex = 0; + + // Replace every line with the correct spacings. + const fixed = comment.value.replace(lineRegExp, () => { + // eslint-disable-next-line unicorn/no-reduce + return partsMatrix[lineIndex++].reduce( + (acc, {string}, index) => { + const spacings = createSequence(' ', expectedPositions[index] - acc.length); + + return acc + (index === 0 ? tagIndentation : spacings) + string; + }, + '', + ); + }); + + return fixer.replaceText(comment, '/*' + fixed + '*/'); + }; +}; + +/** + * Check comment per tag. + * + * @param {object} comment Comment node. + * @param {string} tag Tag string. + * @param {string} tagIndentation Tag indentation. + * @param {Function} report Report function. + */ +const checkCommentPerTag = (comment, tag, tagIndentation, report) => { + const lineRegExp = new RegExp(`.*@${tag}[\\s].*`, 'gm'); + const lines = comment.value.match(lineRegExp); + + if (!lines) { + return; + } + + /** + * A matrix containing the current position and the string of each part for each line. + * 0 - Asterisk. + * 1 - Tag. + * 2 - Type. + * 3 - Variable name. + * 4 - Description (Optional). + */ + const partsMatrix = []; + + /** + * The max length of each part, comparing all the lines. + */ + const partsMaxLength = []; + + // Loop (lines x parts) to populate partsMatrix and partsMaxLength. + lines.forEach((lineString, lineIndex) => { + // All line parts until the first word of the description (if description exists). + matchAll( + lineString, + /\S+/g, + ({0: match, index: position}, partIndex) => { + set(partsMatrix, [lineIndex, partIndex], { + position, + string: partIndex === 4 ? getFullDescription(lineString) : match, + }); + + const partLength = match.length; + const maxLength = partsMaxLength[partIndex]; + + partsMaxLength[partIndex] = maxLength > partLength ? maxLength : partLength; + }, + 5, + ); + }); + + const expectedPositions = getExpectedPositions( + partsMatrix, + partsMaxLength, + tagIndentation.length, + ); + + if (isNotAligned(expectedPositions, partsMatrix)) { + report( + 'Expected JSDoc block lines to be aligned.', + createFixer( + comment, + expectedPositions, + partsMatrix, + lineRegExp, + tagIndentation, + ), + comment.loc, + ); + } +}; + +export default iterateJsdoc(({ + jsdocNode, + report, + indent, +}) => { + // `indent` is whitespace from line 1 (`/**`), so slice and account for "/". + const tagIndentation = indent + ' '; + + ['param', 'arg', 'argument', 'property', 'prop'].forEach((tag) => { + checkCommentPerTag(jsdocNode, tag, tagIndentation, report); + }); +}, { + iterateAllJsdocs: true, + meta: { + docs: { + description: 'Reports invalid alignment of JSDoc block lines.', + url: 'https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-lines-alignment', + }, + fixable: 'whitespace', + type: 'layout', + }, +}); diff --git a/test/rules/assertions/checkLinesAlignment.js b/test/rules/assertions/checkLinesAlignment.js new file mode 100644 index 000000000..179a5e569 --- /dev/null +++ b/test/rules/assertions/checkLinesAlignment.js @@ -0,0 +1,461 @@ +export default { + invalid: [ + { + code: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + errors: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + 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: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + 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: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + 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: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + 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: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + 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: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + 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. + */ + function fn( lorem, sit ) {} + `, + errors: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + output: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + function fn( lorem, sit ) {} + `, + }, + { + code: ` + const object = { + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + fn( lorem, sit ) {} + } + `, + errors: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + output: ` + const object = { + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + fn( lorem, sit ) {} + } + `, + }, + { + code: ` + class ClassName { + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + fn( lorem, sit ) {} + } + `, + errors: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + output: ` + class ClassName { + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + fn( lorem, sit ) {} + } + `, + }, + { + code: ` + /** + * Function description. + * + * @arg {string} lorem Description. + * @arg {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + errors: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + output: ` + /** + * Function description. + * + * @arg {string} lorem Description. + * @arg {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + }, + { + code: ` + /** + * @namespace + * @property {object} defaults Description. + * @property {int} defaults.lorem Description multi words. + */ + const config = { + defaults: { + lorem: 1 + } + } + `, + errors: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + output: ` + /** + * @namespace + * @property {object} defaults Description. + * @property {int} defaults.lorem Description multi words. + */ + const config = { + defaults: { + lorem: 1 + } + } + `, + }, + { + code: ` + /** + * My object. + * + * @typedef {Object} MyObject + * + * @property {string} lorem Description. + * @property {int} sit Description multi words. + */ + `, + errors: [ + { + message: 'Expected JSDoc block lines to be aligned.', + type: 'Block', + }, + ], + output: ` + /** + * My object. + * + * @typedef {Object} MyObject + * + * @property {string} lorem Description. + * @property {int} sit Description multi words. + */ + `, + }, + ], + valid: [ + { + code: ` + /** + * 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 ) => {} + `, + }, + { + code: ` + /** + * @param {string} lorem Description. + * @param {int} sit + */ + const fn = ( lorem, sit ) => {} + `, + }, + { + code: ` + /** + * @param {int} sit + * @param {string} lorem Description. + */ + const fn = ( lorem, sit ) => {} + `, + }, + { + code: ` + /** + * No params. + */ + const fn = () => {} + `, + }, + { + code: ` + const fn = ( lorem, sit ) => {} + `, + }, + { + code: ` + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + function fn( lorem, sit ) {} + `, + }, + { + code: ` + const object = { + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + fn( lorem, sit ) {}, + } + `, + }, + { + code: ` + class ClassName { + /** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + fn( lorem, sit ) {} + } + `, + }, + { + code: ` + /** + * Function description. + * + * @arg {string} lorem Description. + * @arg {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + }, + { + code: ` + /** + * @namespace + * @property {object} defaults Description. + * @property {int} defaults.lorem Description multi words. + */ + const config = { + defaults: { + lorem: 1 + } + } + `, + }, + { + code: ` + /** + * My object. + * + * @typedef {Object} MyObject + * + * @property {string} lorem Description. + * @property {int} sit Description multi words. + */ + `, + }, + ], +}; diff --git a/test/rules/index.js b/test/rules/index.js index 5882f9476..09f4622dd 100644 --- a/test/rules/index.js +++ b/test/rules/index.js @@ -9,6 +9,7 @@ const ruleTester = new RuleTester(); (process.env.npm_config_rule ? process.env.npm_config_rule.split(',') : [ 'check-access', 'check-alignment', + 'check-lines-alignment', 'check-examples', 'check-indentation', 'check-param-names', From 8a407dc63f0fea3e0df1f2e7b1f06126284dd9bb Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Fri, 11 Sep 2020 15:18:13 -0300 Subject: [PATCH 02/12] Add check-lines-alignment documentation --- .README/rules/check-lines-alignment.md | 51 ++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .README/rules/check-lines-alignment.md diff --git a/.README/rules/check-lines-alignment.md b/.README/rules/check-lines-alignment.md new file mode 100644 index 000000000..77041476e --- /dev/null +++ b/.README/rules/check-lines-alignment.md @@ -0,0 +1,51 @@ +### `check-alignment` + +Reports invalid alignment of JSDoc block lines. + +||| +|---|---| +|Context|everywhere| +|Tags|`param`, `arg`, `argument`, `property`, `prop`| + +The following patterns are considered problems: + +````js +/** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ +const fn = ( lorem, sit ) => {} +// Message: Expected JSDoc block lines to be aligned. + +/** + * My object. + * + * @typedef {Object} MyObject + * + * @property {string} lorem Description. + * @property {int} sit Description multi words. + */ +// Message: Expected JSDoc block lines to be aligned. + +The following patterns are not considered problems: + +````js +/** + * Function description. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ +const fn = ( lorem, sit ) => {} + +/** + * My object. + * + * @typedef {Object} MyObject + * + * @property {string} lorem Description. + * @property {int} sit Description multi words. + */ +```` From 82e2cf26a6b54b5939e1d2d3ec5d0134c8d7492c Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Fri, 11 Sep 2020 15:24:48 -0300 Subject: [PATCH 03/12] Remove unused argument --- src/rules/checkLinesAlignment.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/rules/checkLinesAlignment.js b/src/rules/checkLinesAlignment.js index c4d1d75a6..3ffe03cda 100644 --- a/src/rules/checkLinesAlignment.js +++ b/src/rules/checkLinesAlignment.js @@ -45,13 +45,12 @@ const getFullDescription = (lineString) => { /** * Get the expected positions for each part. * - * @param {Array[]} partsMatrix Parts matrix. - * @param {int[]} partsMaxLength Max length of each part. - * @param {int} indentLevel JSDoc indent level. + * @param {int[]} partsMaxLength Max length of each part. + * @param {int} indentLevel JSDoc indent level. * * @returns {int[]} Expected position for each part. */ -const getExpectedPositions = (partsMatrix, partsMaxLength, indentLevel) => { +const getExpectedPositions = (partsMaxLength, indentLevel) => { // eslint-disable-next-line unicorn/no-reduce return partsMaxLength.reduce( (acc, cur, index) => { @@ -164,11 +163,7 @@ const checkCommentPerTag = (comment, tag, tagIndentation, report) => { ); }); - const expectedPositions = getExpectedPositions( - partsMatrix, - partsMaxLength, - tagIndentation.length, - ); + const expectedPositions = getExpectedPositions(partsMaxLength, tagIndentation.length); if (isNotAligned(expectedPositions, partsMatrix)) { report( From c36805e10bf18d6c3230d8604a72cfbceba3bb49 Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Fri, 11 Sep 2020 16:14:15 -0300 Subject: [PATCH 04/12] Fix jsdoc position Iteration already handles that. --- src/rules/checkLinesAlignment.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/rules/checkLinesAlignment.js b/src/rules/checkLinesAlignment.js index 3ffe03cda..7c9210a32 100644 --- a/src/rules/checkLinesAlignment.js +++ b/src/rules/checkLinesAlignment.js @@ -175,7 +175,6 @@ const checkCommentPerTag = (comment, tag, tagIndentation, report) => { lineRegExp, tagIndentation, ), - comment.loc, ); } }; From 3461640f500b1da7dec18da0cfbf5c6d1c5fecb1 Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Fri, 11 Sep 2020 16:25:39 -0300 Subject: [PATCH 05/12] Add WordPress recomendation as example for check-lines-alignment rule --- .README/rules/check-lines-alignment.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.README/rules/check-lines-alignment.md b/.README/rules/check-lines-alignment.md index 77041476e..5d52cd9ac 100644 --- a/.README/rules/check-lines-alignment.md +++ b/.README/rules/check-lines-alignment.md @@ -1,6 +1,7 @@ ### `check-alignment` -Reports invalid alignment of JSDoc block lines. +Reports invalid alignment of JSDoc block lines. This is a +[standard recommended to WordPress code](https://make.wordpress.org/core/handbook/best-practices/inline-documentation-standards/javascript/#aligning-comments), for example. ||| |---|---| From a50a00d12761f65ffb38e32cd336395e20975861 Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Fri, 11 Sep 2020 16:26:04 -0300 Subject: [PATCH 06/12] Fix check-lines-alignment documentation title --- .README/rules/check-lines-alignment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.README/rules/check-lines-alignment.md b/.README/rules/check-lines-alignment.md index 5d52cd9ac..cac730a6b 100644 --- a/.README/rules/check-lines-alignment.md +++ b/.README/rules/check-lines-alignment.md @@ -1,4 +1,4 @@ -### `check-alignment` +### `check-lines-alignment` Reports invalid alignment of JSDoc block lines. This is a [standard recommended to WordPress code](https://make.wordpress.org/core/handbook/best-practices/inline-documentation-standards/javascript/#aligning-comments), for example. From 98ae62cdb48facd14c04f9edc9acff860dc90ebd Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Sat, 12 Sep 2020 13:52:17 -0300 Subject: [PATCH 07/12] Refactor create sequence function --- src/rules/checkLinesAlignment.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/rules/checkLinesAlignment.js b/src/rules/checkLinesAlignment.js index 7c9210a32..24aa51089 100644 --- a/src/rules/checkLinesAlignment.js +++ b/src/rules/checkLinesAlignment.js @@ -3,16 +3,6 @@ import { } from 'lodash'; import iterateJsdoc from '../iterateJsdoc'; -/** - * Create a sequence of chars with a specific size. - * - * @param {string} char The char. - * @param {int} length The length. - */ -const createSequence = (char, length) => { - return new Array(length + 1).join(char); -}; - /** * Aux method until we consider the dev envs support `String.prototype.matchAll` (Node 12+). * @@ -99,7 +89,7 @@ const createFixer = (comment, expectedPositions, partsMatrix, lineRegExp, tagInd // eslint-disable-next-line unicorn/no-reduce return partsMatrix[lineIndex++].reduce( (acc, {string}, index) => { - const spacings = createSequence(' ', expectedPositions[index] - acc.length); + const spacings = ''.padStart(expectedPositions[index] - acc.length, ' '); return acc + (index === 0 ? tagIndentation : spacings) + string; }, From af433fa79ec5197a76e5707784e528f57b91b8be Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Sat, 12 Sep 2020 14:03:38 -0300 Subject: [PATCH 08/12] Add todo comment to remove method when String.prototype.matchAll is supported --- src/rules/checkLinesAlignment.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rules/checkLinesAlignment.js b/src/rules/checkLinesAlignment.js index 24aa51089..3661886b1 100644 --- a/src/rules/checkLinesAlignment.js +++ b/src/rules/checkLinesAlignment.js @@ -10,6 +10,8 @@ import iterateJsdoc from '../iterateJsdoc'; * @param {RegExp} regexp Regular expression to run. * @param {Function} callback Function to be called each iteration. * @param {int} limit Limit of matches that we want to exec. + * + * @todo [engine:node@>=12]: Remove function and use `String.prototype.matchAll` instead. */ const matchAll = (string, regexp, callback, limit) => { let result; From 65512e950e094f0cf1ad4db5e1dc8c3b00b8a97e Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Sat, 12 Sep 2020 14:49:10 -0300 Subject: [PATCH 09/12] Add options to check lines alignment rule "Always" will check for the alignemnt. "Never" is not yet implemented, but will check if there is no more than one space between the parts. --- .README/rules/check-lines-alignment.md | 12 +++ src/rules/checkLinesAlignment.js | 15 ++++ test/rules/assertions/checkLinesAlignment.js | 79 ++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/.README/rules/check-lines-alignment.md b/.README/rules/check-lines-alignment.md index cac730a6b..c9338a6ab 100644 --- a/.README/rules/check-lines-alignment.md +++ b/.README/rules/check-lines-alignment.md @@ -3,9 +3,17 @@ Reports invalid alignment of JSDoc block lines. This is a [standard recommended to WordPress code](https://make.wordpress.org/core/handbook/best-practices/inline-documentation-standards/javascript/#aligning-comments), for example. +#### Options + +This rule allows one optional string argument. If it is `"always"` then a +problem is raised when the lines are not aligned. If it is `"never"` then +a problem should be raised when there is more than one space between the +lines parts. Only the non-default `"always"` is implemented for now. + ||| |---|---| |Context|everywhere| +|Options|(a string matching `"always"|"never"`)| |Tags|`param`, `arg`, `argument`, `property`, `prop`| The following patterns are considered problems: @@ -18,6 +26,7 @@ The following patterns are considered problems: * @param {int} sit Description multi words. */ const fn = ( lorem, sit ) => {} +// Options: ["always"] // Message: Expected JSDoc block lines to be aligned. /** @@ -28,6 +37,7 @@ const fn = ( lorem, sit ) => {} * @property {string} lorem Description. * @property {int} sit Description multi words. */ +// Options: ["always"] // Message: Expected JSDoc block lines to be aligned. The following patterns are not considered problems: @@ -40,6 +50,7 @@ The following patterns are not considered problems: * @param {int} sit Description multi words. */ const fn = ( lorem, sit ) => {} +// Options: ["always"] /** * My object. @@ -49,4 +60,5 @@ const fn = ( lorem, sit ) => {} * @property {string} lorem Description. * @property {int} sit Description multi words. */ +// Options: ["always"] ```` diff --git a/src/rules/checkLinesAlignment.js b/src/rules/checkLinesAlignment.js index 3661886b1..78d37b4c8 100644 --- a/src/rules/checkLinesAlignment.js +++ b/src/rules/checkLinesAlignment.js @@ -174,8 +174,17 @@ const checkCommentPerTag = (comment, tag, tagIndentation, report) => { export default iterateJsdoc(({ jsdocNode, report, + context, indent, }) => { + if (context.options[0] === 'never') { + throw new Error('The `never` option is not yet implemented for this rule.'); + } + + if (context.options[0] !== 'always') { + return; + } + // `indent` is whitespace from line 1 (`/**`), so slice and account for "/". const tagIndentation = indent + ' '; @@ -190,6 +199,12 @@ export default iterateJsdoc(({ url: 'https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-lines-alignment', }, fixable: 'whitespace', + schema: [ + { + enum: ['always', 'never'], + type: 'string', + }, + ], type: 'layout', }, }); diff --git a/test/rules/assertions/checkLinesAlignment.js b/test/rules/assertions/checkLinesAlignment.js index 179a5e569..fbf5083f7 100644 --- a/test/rules/assertions/checkLinesAlignment.js +++ b/test/rules/assertions/checkLinesAlignment.js @@ -16,6 +16,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * Function description. @@ -42,6 +45,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * Function description. @@ -68,6 +74,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * Function description. @@ -94,6 +103,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * Function description. @@ -120,6 +132,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * Function description. @@ -146,6 +161,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * Function description. @@ -172,6 +190,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * Function description. @@ -200,6 +221,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` const object = { /** @@ -230,6 +254,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` class ClassName { /** @@ -258,6 +285,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * Function description. @@ -287,6 +317,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * @namespace @@ -317,6 +350,9 @@ export default { type: 'Block', }, ], + options: [ + 'always', + ], output: ` /** * My object. @@ -340,6 +376,9 @@ export default { */ const fn = ( lorem, sit ) => {} `, + options: [ + 'always', + ], }, { code: ` @@ -351,6 +390,9 @@ export default { */ const fn = ( lorem, sit ) => {} `, + options: [ + 'always', + ], }, { code: ` @@ -360,6 +402,9 @@ export default { */ const fn = ( lorem, sit ) => {} `, + options: [ + 'always', + ], }, { code: ` @@ -369,6 +414,9 @@ export default { */ const fn = ( lorem, sit ) => {} `, + options: [ + 'always', + ], }, { code: ` @@ -377,11 +425,17 @@ export default { */ const fn = () => {} `, + options: [ + 'always', + ], }, { code: ` const fn = ( lorem, sit ) => {} `, + options: [ + 'always', + ], }, { code: ` @@ -393,6 +447,9 @@ export default { */ function fn( lorem, sit ) {} `, + options: [ + 'always', + ], }, { code: ` @@ -406,6 +463,9 @@ export default { fn( lorem, sit ) {}, } `, + options: [ + 'always', + ], }, { code: ` @@ -419,6 +479,9 @@ export default { fn( lorem, sit ) {} } `, + options: [ + 'always', + ], }, { code: ` @@ -430,6 +493,9 @@ export default { */ const fn = ( lorem, sit ) => {} `, + options: [ + 'always', + ], }, { code: ` @@ -444,6 +510,9 @@ export default { } } `, + options: [ + 'always', + ], }, { code: ` @@ -456,6 +525,16 @@ export default { * @property {int} sit Description multi words. */ `, + options: [ + 'always', + ], + }, + { + code: ` + /** + * Not validating without option. + */ + `, }, ], }; From 771d550f8dd586749063c35125a07c044b0d7fa0 Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Sun, 13 Sep 2020 10:48:34 -0300 Subject: [PATCH 10/12] Refactor spaces repeat Co-authored-by: Brett Zamir --- src/rules/checkLinesAlignment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/checkLinesAlignment.js b/src/rules/checkLinesAlignment.js index 78d37b4c8..7d410e34f 100644 --- a/src/rules/checkLinesAlignment.js +++ b/src/rules/checkLinesAlignment.js @@ -91,7 +91,7 @@ const createFixer = (comment, expectedPositions, partsMatrix, lineRegExp, tagInd // eslint-disable-next-line unicorn/no-reduce return partsMatrix[lineIndex++].reduce( (acc, {string}, index) => { - const spacings = ''.padStart(expectedPositions[index] - acc.length, ' '); + const spacings = ' '.repeat(expectedPositions[index] - acc.length); return acc + (index === 0 ? tagIndentation : spacings) + string; }, From 38b8b9db3eae203c41ef34a9dc2ed6aaf31e5a0d Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Sun, 13 Sep 2020 11:03:35 -0300 Subject: [PATCH 11/12] Refactor not implemented option warning Report an error through eslint instead of throw. --- src/rules/checkLinesAlignment.js | 4 +++- test/rules/assertions/checkLinesAlignment.js | 24 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/rules/checkLinesAlignment.js b/src/rules/checkLinesAlignment.js index 7d410e34f..2f0eb65c3 100644 --- a/src/rules/checkLinesAlignment.js +++ b/src/rules/checkLinesAlignment.js @@ -178,7 +178,9 @@ export default iterateJsdoc(({ indent, }) => { if (context.options[0] === 'never') { - throw new Error('The `never` option is not yet implemented for this rule.'); + report('The `never` option is not yet implemented for this rule.'); + + return; } if (context.options[0] !== 'always') { diff --git a/test/rules/assertions/checkLinesAlignment.js b/test/rules/assertions/checkLinesAlignment.js index fbf5083f7..b58917690 100644 --- a/test/rules/assertions/checkLinesAlignment.js +++ b/test/rules/assertions/checkLinesAlignment.js @@ -364,6 +364,26 @@ export default { */ `, }, + { + code: ` + /** + * Not implemented yet. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. + */ + const fn = ( lorem, sit ) => {} + `, + errors: [ + { + message: 'The `never` option is not yet implemented for this rule.', + type: 'Block', + }, + ], + options: [ + 'never', + ], + }, ], valid: [ { @@ -533,7 +553,11 @@ export default { code: ` /** * Not validating without option. + * + * @param {string} lorem Description. + * @param {int} sit Description multi words. */ + const fn = ( lorem, sit ) => {} `, }, ], From 1c1dd685b5a16a8f3b5660b68447502500040c9a Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Sun, 13 Sep 2020 11:06:20 -0300 Subject: [PATCH 12/12] Update check-lines-alignmenment rule to off as recommended It's not a standard used by any project, so the default is off --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index e30642bac..464d576a0 100644 --- a/src/index.js +++ b/src/index.js @@ -48,7 +48,7 @@ export default { 'jsdoc/check-alignment': 'warn', 'jsdoc/check-examples': 'off', 'jsdoc/check-indentation': 'off', - 'jsdoc/check-lines-alignment': 'warn', + 'jsdoc/check-lines-alignment': 'off', 'jsdoc/check-param-names': 'warn', 'jsdoc/check-property-names': 'warn', 'jsdoc/check-syntax': 'off',