diff --git a/src/index.js b/src/index.js index d91180a37..b5e44b031 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,7 @@ import checkAlignment from './rules/checkAlignment'; import checkExamples from './rules/checkExamples'; import checkIndentation from './rules/checkIndentation'; import checkParamNames from './rules/checkParamNames'; +import checkPrefix from './rules/checkPrefix'; import checkSyntax from './rules/checkSyntax'; import checkTagNames from './rules/checkTagNames'; import checkTypes from './rules/checkTypes'; @@ -39,6 +40,7 @@ export default { 'jsdoc/check-examples': 'off', 'jsdoc/check-indentation': 'off', 'jsdoc/check-param-names': 'warn', + 'jsdoc/check-prefix': 'off', 'jsdoc/check-syntax': 'off', 'jsdoc/check-tag-names': 'warn', 'jsdoc/check-types': 'warn', @@ -72,6 +74,7 @@ export default { 'check-examples': checkExamples, 'check-indentation': checkIndentation, 'check-param-names': checkParamNames, + 'check-prefix': checkPrefix, 'check-syntax': checkSyntax, 'check-tag-names': checkTagNames, 'check-types': checkTypes, diff --git a/src/rules/checkPrefix.js b/src/rules/checkPrefix.js new file mode 100644 index 000000000..3b563f6e6 --- /dev/null +++ b/src/rules/checkPrefix.js @@ -0,0 +1,38 @@ +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); + }; + + for (const [index, line] of Object.entries(sourceCode.getText(jsdocNode).split('\n'))) { + const lineNum = parseInt(index, 10); + if (lineNum && !validPrefix.test(line)) { + report('Expected JSDoc block to have the prefix.', fix, { + line: lineNum, + }); + break; + } + } +}, { + iterateAllJsdocs: true, + meta: { + fixable: 'code', + type: 'layout', + }, +}); diff --git a/test/rules/assertions/checkPrefix.js b/test/rules/assertions/checkPrefix.js new file mode 100644 index 000000000..8d363687d --- /dev/null +++ b/test/rules/assertions/checkPrefix.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..cf571a7ef 100644 --- a/test/rules/index.js +++ b/test/rules/index.js @@ -13,6 +13,7 @@ const ruleTester = new RuleTester(); 'check-examples', 'check-indentation', 'check-param-names', + 'check-prefix', 'check-syntax', 'check-tag-names', 'check-types',