diff --git a/.README/README.md b/.README/README.md index 9a0b13bff..405860df7 100644 --- a/.README/README.md +++ b/.README/README.md @@ -44,6 +44,7 @@ Finally, enable all of the rules that you would like to use. "jsdoc/check-examples": 1, "jsdoc/check-indentation": 1, "jsdoc/check-param-names": 1, // Recommended + "jsdoc/require-asterisk-prefix": 1, "jsdoc/check-syntax": 1, "jsdoc/check-tag-names": 1, // Recommended "jsdoc/check-types": 1, // Recommended @@ -337,6 +338,7 @@ only (e.g., to match `Array` if the type is `Array` vs. `Array.`). {"gitdown": "include", "file": "./rules/newline-after-description.md"} {"gitdown": "include", "file": "./rules/no-types.md"} {"gitdown": "include", "file": "./rules/no-undefined-types.md"} +{"gitdown": "include", "file": "./rules/require-asterisk-prefix.md"} {"gitdown": "include", "file": "./rules/require-description-complete-sentence.md"} {"gitdown": "include", "file": "./rules/require-description.md"} {"gitdown": "include", "file": "./rules/require-example.md"} diff --git a/.README/rules/require-asterisk-prefix.md b/.README/rules/require-asterisk-prefix.md new file mode 100644 index 000000000..83b80ad50 --- /dev/null +++ b/.README/rules/require-asterisk-prefix.md @@ -0,0 +1,12 @@ +### `require-asterisk-prefix` + +Requires that each JSDoc line starts with an `*`. + +#### Options + +This rule allows one optional string argument. If it is `"always"` then a problem is raised when there is no asterisk prefix on a given jsdoc line. If it is `"never"` then a problem is raised when there is an asterisk present. The default value is `"always"`. + +||| +|---|---| +|Context|everywhere| +|Tags|N/a| diff --git a/README.md b/README.md index d0e276efe..f9b47782d 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ JSDoc linting rules for ESLint. * [`newline-after-description`](#eslint-plugin-jsdoc-rules-newline-after-description) * [`no-types`](#eslint-plugin-jsdoc-rules-no-types) * [`no-undefined-types`](#eslint-plugin-jsdoc-rules-no-undefined-types) + * [`require-asterisk-prefix`](#eslint-plugin-jsdoc-rules-require-asterisk-prefix) * [`require-description-complete-sentence`](#eslint-plugin-jsdoc-rules-require-description-complete-sentence) * [`require-description`](#eslint-plugin-jsdoc-rules-require-description) * [`require-example`](#eslint-plugin-jsdoc-rules-require-example) @@ -87,6 +88,7 @@ Finally, enable all of the rules that you would like to use. "jsdoc/check-examples": 1, "jsdoc/check-indentation": 1, "jsdoc/check-param-names": 1, // Recommended + "jsdoc/require-asterisk-prefix": 1, "jsdoc/check-syntax": 1, "jsdoc/check-tag-names": 1, // Recommended "jsdoc/check-types": 1, // Recommended @@ -5107,6 +5109,21 @@ function quux () {} ```` + +### require-asterisk-prefix + +Requires that each JSDoc line starts with an `*`. + + +#### Options + +This rule allows one optional string argument. If it is `"always"` then a problem is raised when there is no asterisk prefix on a given jsdoc line. If it is `"never"` then a problem is raised when there is an asterisk present. The default value is `"always"`. + +||| +|---|---| +|Context|everywhere| +|Tags|N/a| + ### require-description-complete-sentence @@ -5121,10 +5138,10 @@ tag descriptions are written in complete sentences, i.e., * A colon or semi-colon followed by two line breaks is still part of the containing paragraph (unlike normal dual line breaks). - + #### Options - + ##### tags If you want additional tags to be checked for their descriptions, you may @@ -5612,7 +5629,7 @@ Requires that all functions have a description. `"tag"`) must have a non-empty description that explains the purpose of the method. - + #### Options An options object may have any of the following properties: @@ -5897,25 +5914,25 @@ Requires that all functions have examples. * All functions must have one or more `@example` tags. * Every example tag must have a non-empty description that explains the method's usage. - + #### Options This rule has an object option. - + ##### exemptedBy Array of tags (e.g., `['type']`) whose presence on the document block avoids the need for an `@example`. Defaults to an empty array. - + ##### avoidExampleOnConstructors Set to `true` to avoid the need for an example on a constructor (whether indicated as such by a jsdoc tag or by being within an ES6 `class`). Defaults to `false`. - + ##### contexts Set this to an array of strings representing the AST context @@ -6093,7 +6110,7 @@ function quux () { Requires a hyphen before the `@param` description. - + #### Options This rule takes one optional string argument. If it is `"always"` then a problem is raised when there is no hyphen before the description. If it is `"never"` then a problem is raised when there is a hyphen before the description. The default value is `"always"`. @@ -6199,7 +6216,7 @@ function quux () { Checks for presence of jsdoc comments, on class declarations as well as functions. - + #### Options Accepts one optional options object with the following optional keys. @@ -7387,7 +7404,7 @@ function quux (foo) { Requires that all function parameters are documented. - + #### Options An options object accepts one optional property: @@ -8487,7 +8504,7 @@ Requires returns are documented. Will also report if multiple `@returns` tags are present. - + #### Options - `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the document @@ -8952,7 +8969,7 @@ Also impacts behaviors on namepath (or event)-defining and pointing tags: allow `#`, `.`, or `~` at the end (which is not allowed at the end of normal paths). - + #### Options - `allowEmptyNamepaths` (default: true) - Set to `false` to disallow diff --git a/src/index.js b/src/index.js index d91180a37..a7bfdfd9a 100644 --- a/src/index.js +++ b/src/index.js @@ -14,13 +14,14 @@ import matchDescription from './rules/matchDescription'; import newlineAfterDescription from './rules/newlineAfterDescription'; import noTypes from './rules/noTypes'; import noUndefinedTypes from './rules/noUndefinedTypes'; -import requireDescriptionCompleteSentence from './rules/requireDescriptionCompleteSentence'; +import requireAsteriskPrefix from './rules/requireAsteriskPrefix'; import requireDescription from './rules/requireDescription'; +import requireDescriptionCompleteSentence from './rules/requireDescriptionCompleteSentence'; import requireExample from './rules/requireExample'; import requireHyphenBeforeParamDescription from './rules/requireHyphenBeforeParamDescription'; -import requireParamName from './rules/requireParamName'; import requireParam from './rules/requireParam'; import requireParamDescription from './rules/requireParamDescription'; +import requireParamName from './rules/requireParamName'; import requireParamType from './rules/requireParamType'; import requireReturns from './rules/requireReturns'; import requireReturnsCheck from './rules/requireReturnsCheck'; @@ -49,6 +50,7 @@ export default { 'jsdoc/newline-after-description': 'warn', 'jsdoc/no-types': 'off', 'jsdoc/no-undefined-types': 'warn', + 'jsdoc/require-asterisk-prefix': 'off', 'jsdoc/require-description': 'off', 'jsdoc/require-description-complete-sentence': 'off', 'jsdoc/require-example': 'off', @@ -82,6 +84,7 @@ export default { 'newline-after-description': newlineAfterDescription, 'no-types': noTypes, 'no-undefined-types': noUndefinedTypes, + 'require-asterisk-prefix': requireAsteriskPrefix, 'require-description': requireDescription, 'require-description-complete-sentence': requireDescriptionCompleteSentence, 'require-example': requireExample, diff --git a/src/rules/requireAsteriskPrefix.js b/src/rules/requireAsteriskPrefix.js new file mode 100644 index 000000000..5bd4f63f1 --- /dev/null +++ b/src/rules/requireAsteriskPrefix.js @@ -0,0 +1,41 @@ +import iterateJsdoc from '../iterateJsdoc'; + +const prefixMatch = /^(\s+)(?:\*( ?))?/u; +const validPrefix = /^\s+\*(?:\/?$| )/u; + +export default iterateJsdoc(({ + sourceCode, + jsdocNode, + report, +}) => { + const fix = (fixer) => { + const replacement = sourceCode.getText(jsdocNode).split('\n') + .map((line, index) => { + return index && !validPrefix.test(line) ? line.replace(prefixMatch, (_, $1, $2) => { + return `${$1}*${$2 || ' '}`; + }) : line; + }) + .join('\n'); + + return fixer.replaceText(jsdocNode, replacement); + }; + + sourceCode.getText(jsdocNode).split('\n').some((line, index) => { + const lineNum = parseInt(index, 10); + if (lineNum && !validPrefix.test(line)) { + report('Expected JSDoc block to have the prefix.', fix, { + line: lineNum, + }); + + return true; + } + + return false; + }); +}, { + iterateAllJsdocs: true, + meta: { + fixable: 'code', + type: 'layout', + }, +}); diff --git a/test/rules/assertions/requireAsteriskPrefix.js b/test/rules/assertions/requireAsteriskPrefix.js new file mode 100644 index 000000000..8d363687d --- /dev/null +++ b/test/rules/assertions/requireAsteriskPrefix.js @@ -0,0 +1,91 @@ +export default { + invalid: [ + { + code: ` + + /** + @param {Number} foo + */ + function quux (foo) { + // with spaces + } + `, + errors: [ + { + line: 4, + message: 'Expected JSDoc block to have the prefix.', + }, + ], + output: ` + + /** + * @param {Number} foo + */ + function quux (foo) { + // with spaces + } + `, + }, + { + code: ` + /** + @param {Number} foo + */function quux (foo) { + // with spaces + } + `, + errors: [ + { + line: 3, + message: 'Expected JSDoc block to have the prefix.', + }, + ], + output: ` + /** + * @param {Number} foo + */function quux (foo) { + // with spaces + } + `, + }, + ], + valid: [ + { + code: ` + /** + * Desc + * + * @param {Number} foo + * This is more comment. + */ + function quux (foo) { + + } + `, + }, + { + code: ` + /** + * Desc + * + * @param {{ + * foo: Bar, + * bar: Baz + * }} foo + * + */ + function quux (foo) { + + } + `, + }, + { + code: ` + /* <- JSDoc must start with 2 stars. + So this is unchecked. + */ + function quux (foo) {} + `, + }, + ], +}; diff --git a/test/rules/index.js b/test/rules/index.js index 57d114389..2ebbad0b5 100644 --- a/test/rules/index.js +++ b/test/rules/index.js @@ -23,6 +23,7 @@ const ruleTester = new RuleTester(); 'newline-after-description', 'no-types', 'no-undefined-types', + 'require-asterisk-prefix', 'require-description', 'require-description-complete-sentence', 'require-example',