From 682b6bd6d42ad0797de40647d19a78e60fd6d852 Mon Sep 17 00:00:00 2001 From: Kunal Nagpal Date: Fri, 12 May 2017 19:20:43 +0530 Subject: [PATCH] feat: add rule require-example (#35) * feat: Add require-example rule :tada: * test: Add require-example tests * docs: Added documentation for require-example :memo: --- .README/README.md | 3 + .README/rules/require-example.md | 13 +++++ src/index.js | 3 + src/rules/requireExample.js | 26 +++++++++ test/rules/assertions/requireExample.js | 74 +++++++++++++++++++++++++ test/rules/index.js | 1 + 6 files changed, 120 insertions(+) create mode 100644 .README/rules/require-example.md create mode 100644 src/rules/requireExample.js create mode 100644 test/rules/assertions/requireExample.js diff --git a/.README/README.md b/.README/README.md index 45ba3e3d3..386f8fc2b 100644 --- a/.README/README.md +++ b/.README/README.md @@ -19,6 +19,7 @@ This table maps the rules between `eslint-plugin-jsdoc` and `jscs-jsdoc`. | [`check-types`](https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-check-types) | [`checkTypes`](https://github.com/jscs-dev/jscs-jsdoc#checktypes) | | [`newline-after-description`](https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-newline-after-description) | [`requireNewlineAfterDescription`](https://github.com/jscs-dev/jscs-jsdoc#requirenewlineafterdescription) and [`disallowNewlineAfterDescription`](https://github.com/jscs-dev/jscs-jsdoc#disallownewlineafterdescription) | | [`require-description-complete-sentence`](https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-description-complete-sentence) | [`requireDescriptionCompleteSentence`](https://github.com/jscs-dev/jscs-jsdoc#requiredescriptioncompletesentence) | +| [`require-example`](https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-example) | N/A | | [`require-hyphen-before-param-description`](https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-hyphen-before-param-description) | [`requireHyphenBeforeDescription`](https://github.com/jscs-dev/jscs-jsdoc#requirehyphenbeforedescription) | | [`require-param`](https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-param) | [`checkParamExistence`](https://github.com/jscs-dev/jscs-jsdoc#checkparamexistence) | | [`require-param-description`](https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-param-description) | [`requireParamDescription`](https://github.com/jscs-dev/jscs-jsdoc#requireparamdescription) | @@ -68,6 +69,7 @@ Finally, enable all of the rules that you would like to use. "jsdoc/check-types": 1, "jsdoc/newline-after-description": 1, "jsdoc/require-description-complete-sentence": 1, + "jsdoc/require-example": 1, "jsdoc/require-hyphen-before-param-description": 1, "jsdoc/require-param": 1, "jsdoc/require-param-description": 1, @@ -123,6 +125,7 @@ Use `settings.jsdoc.additionalTagNames` to configure additional, allowed JSDoc t {"gitdown": "include", "file": "./rules/check-types.md"} {"gitdown": "include", "file": "./rules/newline-after-description.md"} {"gitdown": "include", "file": "./rules/require-description-complete-sentence.md"} +{"gitdown": "include", "file": "./rules/require-example.md"} {"gitdown": "include", "file": "./rules/require-hyphen-before-param-description.md"} {"gitdown": "include", "file": "./rules/require-param.md"} {"gitdown": "include", "file": "./rules/require-param-description.md"} diff --git a/.README/rules/require-example.md b/.README/rules/require-example.md new file mode 100644 index 000000000..b35369886 --- /dev/null +++ b/.README/rules/require-example.md @@ -0,0 +1,13 @@ +### `require-example` + +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. + +||| +|---|---| +|Context|`ArrowFunctionExpression`, `FunctionDeclaration`, `FunctionExpression`| +|Tags|`example`| + + diff --git a/src/index.js b/src/index.js index 2f4424287..3c66cd184 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,7 @@ import checkTagNames from './rules/checkTagNames'; import checkTypes from './rules/checkTypes'; import newlineAfterDescription from './rules/newlineAfterDescription'; import requireDescriptionCompleteSentence from './rules/requireDescriptionCompleteSentence'; +import requireExample from './rules/requireExample'; import requireHyphenBeforeParamDescription from './rules/requireHyphenBeforeParamDescription'; import requireParam from './rules/requireParam'; import requireParamDescription from './rules/requireParamDescription'; @@ -17,6 +18,7 @@ export default { 'check-types': checkTypes, 'newline-after-description': newlineAfterDescription, 'require-description-complete-sentence': requireDescriptionCompleteSentence, + 'require-example': requireExample, 'require-hyphen-before-param-description': requireHyphenBeforeParamDescription, 'require-param': requireParam, 'require-param-description': requireParamDescription, @@ -30,6 +32,7 @@ export default { 'check-types': 0, 'newline-after-description': 0, 'require-description-complete-sentence': 0, + 'require-example': 0, 'require-hyphen-before-param-description': 0, 'require-param': 0, 'require-param-description': 0, diff --git a/src/rules/requireExample.js b/src/rules/requireExample.js new file mode 100644 index 000000000..b67c6b47c --- /dev/null +++ b/src/rules/requireExample.js @@ -0,0 +1,26 @@ +import _ from 'lodash'; +import iterateJsdoc from '../iterateJsdoc'; + +export default iterateJsdoc(({ + jsdoc, + report, + utils +}) => { + const targetTagName = utils.getPreferredTagName('example'); + + const functionExamples = _.filter(jsdoc.tags, { + tag: targetTagName + }); + + if (_.isEmpty(functionExamples)) { + return report('Missing JSDoc @' + targetTagName + ' declaration.'); + } + + return _.forEach(functionExamples, (example) => { + const exampleContent = _.compact((example.name + ' ' + example.description).trim().split('\n')); + + if (_.isEmpty(exampleContent)) { + report('Missing JSDoc @' + targetTagName + ' description.'); + } + }); +}); diff --git a/test/rules/assertions/requireExample.js b/test/rules/assertions/requireExample.js new file mode 100644 index 000000000..99b9638ad --- /dev/null +++ b/test/rules/assertions/requireExample.js @@ -0,0 +1,74 @@ +/* eslint-disable no-restricted-syntax */ + +export default { + invalid: [ + { + code: ` + /** + * + */ + function quux () { + + } + `, + errors: [ + { + message: 'Missing JSDoc @example declaration.' + } + ] + }, + { + code: ` + /** + * @example + */ + function quux () { + + } + `, + errors: [ + { + message: 'Missing JSDoc @example description.' + } + ] + } + ], + valid: [ + { + code: ` + /** + * @example + * // arbitrary example content + */ + function quux () { + + } + ` + }, + { + code: ` + /** + * @example + * quux(); // does something useful + */ + function quux () { + + } + ` + }, + { + code: ` + /** + * @example Valid usage + * quux(); // does something useful + * + * @example Invalid usage + * quux('random unwanted arg'); // results in an error + */ + function quux () { + + } + ` + } + ] +}; diff --git a/test/rules/index.js b/test/rules/index.js index b93000c0b..6b1fcc44e 100644 --- a/test/rules/index.js +++ b/test/rules/index.js @@ -12,6 +12,7 @@ _.forEach([ 'check-types', 'newline-after-description', 'require-description-complete-sentence', + 'require-example', 'require-hyphen-before-param-description', 'require-param', 'require-param-description',