Skip to content

Commit

Permalink
feat(require-yields): add options to check that next has document…
Browse files Browse the repository at this point in the history
…ation
  • Loading branch information
brettz9 committed Jan 23, 2021
1 parent e06fddd commit 15daa12
Show file tree
Hide file tree
Showing 6 changed files with 606 additions and 60 deletions.
48 changes: 38 additions & 10 deletions .README/rules/require-yields.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ Requires that yields are documented.

Will also report if multiple `@yields` tags are present.

See the `next`, `forceRequireNext`, and `nextWithGeneratorTag` options for an
option to expect a non-standard `@next` tag.

Note that there is currently no `yield` equivalent to the
`require-returns-check` rule to ensure that if a `@yields` is present that a
`yield` (or `yield` with a value) is present in the function body (or that if
a `@next` is present that there is a `yield` with a return value present).

Please also note that JavaScript does allow generators not to have `yield`
(e.g., with just a return or even no explicit return), but if you want to
enforce that all generators have a `yield` in the function body, you can
use the ESLint
[`require-yield`](https://eslint.org/docs/rules/require-yield) rule.

#### Options

- `exemptedBy` - Array of tags (e.g., `['type']`) whose presence on the
Expand All @@ -12,15 +26,10 @@ Will also report if multiple `@yields` tags are present.
so be sure to add back `inheritdoc` if you wish its presence to cause
exemption of the rule.
- `forceRequireYields` - Set to `true` to always insist on
`@yields` documentation even if there are only expressionless `yield`
statements in the function. May be desired to flag that a project is aware
of an `undefined`/`void` yield. Defaults to `false`.
Note that unlike `require-returns`, `require-yields` `forceRequire*` option
does not impose the requirement that all generators have a `yield` (since it
is possible a generator may not have even an implicit `yield` and merely
return). If you always want a `yield` present (and thus for this rule to
report the need for docs), you should also use the ESLint
[`require-yield`](https://eslint.org/docs/rules/require-yield) rule.
`@yields` documentation for generators even if there are only
expressionless `yield` statements in the function. May be desired to flag
that a project is aware of an `undefined`/`void` yield. Defaults to
`false`.
- `contexts` - Set this to an array of strings representing the AST context
where you wish the rule to be applied.
Overrides the default contexts (see below). Set to `"any"` if you want
Expand All @@ -36,14 +45,33 @@ Will also report if multiple `@yields` tags are present.
- `withGeneratorTag` - If a `@generator` tag is present on a block, require
`@yields`/`@yield`. Defaults to `true`. See `contexts` to `any` if you want
to catch `@generator` with `@callback` or such not attached to a function.
- `next` - If `true`, this option will insist that any use of a `yield` return
value (e.g., `const rv = yield;` or `const rv = yield value;`) has a
(non-standard) `@next` tag (in addition to any `@yields` tag) so as to be
able to document the type expected to be supplied into the iterator
(the `Generator` iterator that is returned by the call to the generator
function) to the iterator (e.g., `it.next(value)`). The tag will not be
expected if the generator function body merely has plain `yield;` or
`yield value;` statements without returning the values. Defaults to
`false`.
- `forceRequireNext` - Set to `true` to always insist on
`@next` documentation even if there are no `yield` statements in the
function or none return values. May be desired to flag that a project is
aware of the expected yield return being `undefined`. Defaults to `false`.
- `nextWithGeneratorTag` - If a `@generator` tag is present on a block, require
(non-standard ) `@next` (see `next` option). This will require using `void`
or `undefined` in cases where generators do not use the `next()`-supplied
incoming `yield`-returned value. Defaults to `false`. See `contexts` to
`any` if you want to catch `@generator` with `@callback` or such not
attached to a function.

|||
|---|---|
|Context|Generator functions (`FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled)|
|Tags|`yields`|
|Aliases|`yield`|
|Recommended|true|
| Options | `contexts`, `exemptedBy`, `withGeneratorTag`, `forceRequireYields` |
| Options | `contexts`, `exemptedBy`, `withGeneratorTag`, `nextWithGeneratorTag`, `forceRequireYields`, `next` |
| Settings | `overrideReplacesDocs`, `augmentsExtendsReplacesDocs`, `implementsReplacesDocs` |

<!-- assertions requireYields -->
181 changes: 171 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15114,6 +15114,20 @@ Requires that yields are documented.

Will also report if multiple `@yields` tags are present.

See the `next`, `forceRequireNext`, and `nextWithGeneratorTag` options for an
option to expect a non-standard `@next` tag.

Note that there is currently no `yield` equivalent to the
`require-returns-check` rule to ensure that if a `@yields` is present that a
`yield` (or `yield` with a value) is present in the function body (or that if
a `@next` is present that there is a `yield` with a return value present).

Please also note that JavaScript does allow generators not to have `yield`
(e.g., with just a return or even no explicit return), but if you want to
enforce that all generators have a `yield` in the function body, you can
use the ESLint
[`require-yield`](https://eslint.org/docs/rules/require-yield) rule.

<a name="eslint-plugin-jsdoc-rules-require-yields-options-31"></a>
#### Options

Expand All @@ -15123,15 +15137,10 @@ Will also report if multiple `@yields` tags are present.
so be sure to add back `inheritdoc` if you wish its presence to cause
exemption of the rule.
- `forceRequireYields` - Set to `true` to always insist on
`@yields` documentation even if there are only expressionless `yield`
statements in the function. May be desired to flag that a project is aware
of an `undefined`/`void` yield. Defaults to `false`.
Note that unlike `require-returns`, `require-yields` `forceRequire*` option
does not impose the requirement that all generators have a `yield` (since it
is possible a generator may not have even an implicit `yield` and merely
return). If you always want a `yield` present (and thus for this rule to
report the need for docs), you should also use the ESLint
[`require-yield`](https://eslint.org/docs/rules/require-yield) rule.
`@yields` documentation for generators even if there are only
expressionless `yield` statements in the function. May be desired to flag
that a project is aware of an `undefined`/`void` yield. Defaults to
`false`.
- `contexts` - Set this to an array of strings representing the AST context
where you wish the rule to be applied.
Overrides the default contexts (see below). Set to `"any"` if you want
Expand All @@ -15147,14 +15156,33 @@ Will also report if multiple `@yields` tags are present.
- `withGeneratorTag` - If a `@generator` tag is present on a block, require
`@yields`/`@yield`. Defaults to `true`. See `contexts` to `any` if you want
to catch `@generator` with `@callback` or such not attached to a function.
- `next` - If `true`, this option will insist that any use of a `yield` return
value (e.g., `const rv = yield;` or `const rv = yield value;`) has a
(non-standard) `@next` tag (in addition to any `@yields` tag) so as to be
able to document the type expected to be supplied into the iterator
(the `Generator` iterator that is returned by the call to the generator
function) to the iterator (e.g., `it.next(value)`). The tag will not be
expected if the generator function body merely has plain `yield;` or
`yield value;` statements without returning the values. Defaults to
`false`.
- `forceRequireNext` - Set to `true` to always insist on
`@next` documentation even if there are no `yield` statements in the
function or none return values. May be desired to flag that a project is
aware of the expected yield return being `undefined`. Defaults to `false`.
- `nextWithGeneratorTag` - If a `@generator` tag is present on a block, require
(non-standard ) `@next` (see `next` option). This will require using `void`
or `undefined` in cases where generators do not use the `next()`-supplied
incoming `yield`-returned value. Defaults to `false`. See `contexts` to
`any` if you want to catch `@generator` with `@callback` or such not
attached to a function.

|||
|---|---|
|Context|Generator functions (`FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled)|
|Tags|`yields`|
|Aliases|`yield`|
|Recommended|true|
| Options | `contexts`, `exemptedBy`, `withGeneratorTag`, `forceRequireYields` |
| Options | `contexts`, `exemptedBy`, `withGeneratorTag`, `nextWithGeneratorTag`, `forceRequireYields`, `next` |
| Settings | `overrideReplacesDocs`, `augmentsExtendsReplacesDocs`, `implementsReplacesDocs` |

The following patterns are considered problems:
Expand All @@ -15169,6 +15197,43 @@ function * quux (foo) {
}
// Message: Missing JSDoc @yields declaration.

/**
* @yields
*/
function * quux (foo) {

const retVal = yield foo;
}
// Options: [{"next":true}]
// Message: Missing JSDoc @next declaration.

/**
* @yields
*/
function * quux (foo) {

const retVal = yield;
}
// Options: [{"next":true}]
// Message: Missing JSDoc @next declaration.

/**
* @yields {void}
*/
function * quux () {
}
// Options: [{"forceRequireNext":true}]
// Message: Missing JSDoc @next declaration.

/**
* @yields {void}
*/
function * quux () {
yield;
}
// Options: [{"forceRequireNext":true}]
// Message: Missing JSDoc @next declaration.

/**
*
*/
Expand All @@ -15187,6 +15252,27 @@ function * quux (foo) {
// Settings: {"jsdoc":{"tagNamePreference":{"yields":"yield"}}}
// Message: Missing JSDoc @yield declaration.

/**
* @yields
*/
function * quux (foo) {
const val = yield foo;
}
// Settings: {"jsdoc":{"tagNamePreference":{"next":"yield-returns"}}}
// Options: [{"next":true}]
// Message: Missing JSDoc @yield-returns declaration.

/**
* @yields
* @next
*/
function * quux () {
const ret = yield 5;
}
// Settings: {"jsdoc":{"tagNamePreference":{"next":false}}}
// Options: [{"next":true}]
// Message: Unexpected tag `@next`

/**
*
*/
Expand Down Expand Up @@ -15317,6 +15403,13 @@ async function * foo(a) {
// Options: [{"contexts":["any"],"withGeneratorTag":true}]
// Message: Missing JSDoc @yields declaration.

/**
* @generator
* @yields
*/
// Options: [{"contexts":["any"],"nextWithGeneratorTag":true}]
// Message: Missing JSDoc @next declaration.

/**
*
*/
Expand Down Expand Up @@ -15629,6 +15722,14 @@ function quux () {
}
// Options: [{"forceRequireYields":true}]

/**
* @yields {void}
* @next {void}
*/
function * quux () {
}
// Options: [{"forceRequireNext":true}]

/**
* @yields {void}
*/
Expand Down Expand Up @@ -15728,24 +15829,84 @@ async function * foo (a) {
*/
// Options: [{"withGeneratorTag":true}]

/**
* @generator
*/
// Options: [{"nextWithGeneratorTag":true}]

/**
* @generator
* @yields
*/
// Options: [{"contexts":["any"],"withGeneratorTag":true}]

/**
* @generator
* @yields
* @next
*/
// Options: [{"contexts":["any"],"nextWithGeneratorTag":true}]

/**
* @generator
*/
// Options: [{"contexts":["any"],"withGeneratorTag":false}]

/**
* @generator
* @yields
*/
// Options: [{"contexts":["any"],"nextWithGeneratorTag":false}]

/**
* @yields
*/
function * quux (foo) {

const a = yield foo;
}

/**
* @yields
* @next
*/
function * quux (foo) {
let a = yield;
}
// Options: [{"next":true}]

/**
* @yields
* @next
*/
function * quux (foo) {
const a = yield foo;
}
// Options: [{"next":true}]

/**
*
*/
// Options: [{"contexts":["any"],"nextWithGeneratorTag":true}]

/**
*
*/
// Options: [{"contexts":["any"],"next":true}]

/**
*
*/
function quux () {}
// Options: [{"contexts":["any"],"next":true}]

/**
* @yields {void}
*/
function * quux () {
yield;
}
// Options: [{"next":true}]
````


Expand Down
4 changes: 4 additions & 0 deletions src/iterateJsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,10 @@ const getUtils = (
return jsdocUtils.hasYieldValue(node);
};

utils.hasYieldReturnValue = () => {
return jsdocUtils.hasYieldValue(node, true);
};

utils.hasThrowValue = () => {
return jsdocUtils.hasThrowValue(node);
};
Expand Down

0 comments on commit 15daa12

Please sign in to comment.