Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add check-examples replacement processor #1275

Merged
merged 1 commit into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .README/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ See [Settings](./docs/settings.md#readme).

See [Advanced](./docs/advanced.md#readme).

## Processors

See our `@example` and other item [processors](./docs/processors.md#readme).

## Rules

Problems reported by rules which have a wrench :wrench: below can be fixed automatically by running ESLint on the command line with `--fix` option.
Expand Down
143 changes: 143 additions & 0 deletions .README/processors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
## Processors

Normally JavaScript content inside JSDoc tags is not discoverable by ESLint.
`eslint-plugin-jsdoc` offers a processor which allows ESLint to parse `@example`
and other tag text for JavaScript so that it can be linted.

The approach below works in ESLint 9. For ESLint 7, please see our [`check-examples`](./rules/check-examples.md#readme) rule.

The approach requires that we first indicate the JavaScript files that will be checked for `@example` tags.

```js
export default [
{
files: ['**/*.js'],
plugins: {
examples: getJsdocProcessorPlugin({
// Enable these options if you want the `someDefault` inside of the
// following to be checked in addition to `@example`:
// 1. `@default someDefault`
// 2. `@param [val=someDefault]`,
// 3. `@property [val=someDefault]`
// checkDefaults: true,
// checkParams: true,
// checkProperties: true
})
},
processor: 'examples/examples'
},
],
```

Now you can target the JavaScript inside these `@example` or default blocks
by the following:

```js
// Since `@example` JavaScript often follows the same rules as JavaScript in
// Markdown, we use the `.md` extension as the parent by default:
{
files: ['**/*.md/*.js'],
rules: {
// Enable or disable rules for `@example` JavaScript here
}
},
{
files: ['**/*.jsdoc-defaults', '**/*.jsdoc-params', '**/*.jsdoc-properties'],
rules: {
// Enable or disable rules for `@default`, `@param`, or `@property`
// JavaScript here
}
}
```

Alternatively you can just use our built-in configs which do the above for you:

```js
import jsdoc from 'eslint-plugin-jsdoc';

export default [
...index.configs.examples

// Or for @default, @param and @property default expression processing
// ...index.configs['default-expressions']

// Or for both, use:
// ...jsdoc.configs['examples-and-default-expressions'],
];
```

These configs also disable certain rules which are rarely useful in an
`@example` or default context. For example both kinds disable the rule
`no-unused-vars` since it is common for short demos to show how to declare
a variable, but not how to use it.

Default expressions are usually even more strict as they are typically not
going to form a whole statement, but just an expression. With the following:

```js
/**
* @param [abc=someDefault]
*/
function quux (abc) {}
```

...`someDefault` can be checked as JavaScript, but we don't want rules like
`no-unused-expressions` firing, since we're not going to use the expression
here.

For defaults, a couple rules are enabled which are usually useful:

- `quotes` - Set to `double`. It is more common within this
context for double quotes to be used.
- `semi` - Set to 'never' since a semi-colon is not desirable in this context.

### Options

#### `checkDefaults`

Whether to check `@default` tags. Defaults to `false`.

#### `checkExamples`

Whether to check `@example` tags. Defaults to `true`.

#### `checkParams`

Whether to check `@param [name=someDefaultValue]` content. Defaults to `false`.

#### `checkProperties`

Whether to check `@property [name=someDefaultValue]` content. Defaults to `false`.

#### `captionRequired`

Whether to require the JSDoc `<caption></caption>` content inside the `@example`
tag. Defaults to `false`.

#### `paddedIndent`

The number of spaces to assume at the beginning of each line. Defaults to 0. Should
only have an effect on whitespace-based rules.

#### `matchingFileName`
#### `matchingFileNameDefaults`
#### `matchingFileNameParams`
#### `matchingFileNameProperties`

See the [`check-examples`](./rules/check-examples.md#readme) option of the
same name.

#### `exampleCodeRegex` and `rejectExampleCodeRegex`

See the [`check-examples`](./rules/check-examples.md#readme) option of the
same name.

#### `sourceType`

Whether to use "script" or "module" with the parser. Defaults to `"module"`.

#### `parser`

An alternative parser which has a `parseForESLint` method and returns the AST
on the `ast` property (like `typescript-eslint`). Defaults to using ESLint's
Espree parser.
4 changes: 2 additions & 2 deletions .README/rules/check-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

{"gitdown": "contents", "rootId": "check-examples"}

> **NOTE**: This rule currently does not work in ESLint 8 (we are waiting for
> [issue 14745](https://github.com/eslint/eslint/issues/14745)).
> **NOTE**: This rule only works in ESLint 7. For ESLint 9, please see our
> [processors](../processors.md) section.

Ensures that (JavaScript) examples within JSDoc adhere to ESLint rules. Also
has options to lint the default values of optional `@param`/`@arg`/`@argument`
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ JSDoc linting rules for ESLint.
* [Options](#user-content-eslint-plugin-jsdoc-options)
* [Settings](#user-content-eslint-plugin-jsdoc-settings)
* [Advanced](#user-content-eslint-plugin-jsdoc-advanced)
* [Processors](#user-content-eslint-plugin-jsdoc-processors)
* [Rules](#user-content-eslint-plugin-jsdoc-rules)


Expand Down Expand Up @@ -241,6 +242,12 @@ See [Settings](./docs/settings.md#readme).

See [Advanced](./docs/advanced.md#readme).

<a name="user-content-eslint-plugin-jsdoc-processors"></a>
<a name="eslint-plugin-jsdoc-processors"></a>
## Processors

See our `@example` and other item [processors](./docs/processors.md#readme).

<a name="user-content-eslint-plugin-jsdoc-rules"></a>
<a name="eslint-plugin-jsdoc-rules"></a>
## Rules
Expand Down
173 changes: 173 additions & 0 deletions docs/processors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<a name="user-content-processors"></a>
<a name="processors"></a>
## Processors

Normally JavaScript content inside JSDoc tags is not discoverable by ESLint.
`eslint-plugin-jsdoc` offers a processor which allows ESLint to parse `@example`
and other tag text for JavaScript so that it can be linted.

The approach below works in ESLint 9. For ESLint 7, please see our [`check-examples`](./rules/check-examples.md#readme) rule.

The approach requires that we first indicate the JavaScript files that will be checked for `@example` tags.

```js
export default [
{
files: ['**/*.js'],
plugins: {
examples: getJsdocProcessorPlugin({
// Enable these options if you want the `someDefault` inside of the
// following to be checked in addition to `@example`:
// 1. `@default someDefault`
// 2. `@param [val=someDefault]`,
// 3. `@property [val=someDefault]`
// checkDefaults: true,
// checkParams: true,
// checkProperties: true
})
},
processor: 'examples/examples'
},
],
```

Now you can target the JavaScript inside these `@example` or default blocks
by the following:

```js
// Since `@example` JavaScript often follows the same rules as JavaScript in
// Markdown, we use the `.md` extension as the parent by default:
{
files: ['**/*.md/*.js'],
rules: {
// Enable or disable rules for `@example` JavaScript here
}
},
{
files: ['**/*.jsdoc-defaults', '**/*.jsdoc-params', '**/*.jsdoc-properties'],
rules: {
// Enable or disable rules for `@default`, `@param`, or `@property`
// JavaScript here
}
}
```

Alternatively you can just use our built-in configs which do the above for you:

```js
import jsdoc from 'eslint-plugin-jsdoc';

export default [
...index.configs.examples

// Or for @default, @param and @property default expression processing
// ...index.configs['default-expressions']

// Or for both, use:
// ...jsdoc.configs['examples-and-default-expressions'],
];
```

These configs also disable certain rules which are rarely useful in an
`@example` or default context. For example both kinds disable the rule
`no-unused-vars` since it is common for short demos to show how to declare
a variable, but not how to use it.

Default expressions are usually even more strict as they are typically not
going to form a whole statement, but just an expression. With the following:

```js
/**
* @param [abc=someDefault]
*/
function quux (abc) {}
```

...`someDefault` can be checked as JavaScript, but we don't want rules like
`no-unused-expressions` firing, since we're not going to use the expression
here.

For defaults, a couple rules are enabled which are usually useful:

- `quotes` - Set to `double`. It is more common within this
context for double quotes to be used.
- `semi` - Set to 'never' since a semi-colon is not desirable in this context.

<a name="user-content-processors-options"></a>
<a name="processors-options"></a>
### Options

<a name="user-content-processors-options-checkdefaults"></a>
<a name="processors-options-checkdefaults"></a>
#### <code>checkDefaults</code>

Whether to check `@default` tags. Defaults to `false`.

<a name="user-content-processors-options-checkexamples"></a>
<a name="processors-options-checkexamples"></a>
#### <code>checkExamples</code>

Whether to check `@example` tags. Defaults to `true`.

<a name="user-content-processors-options-checkparams"></a>
<a name="processors-options-checkparams"></a>
#### <code>checkParams</code>

Whether to check `@param [name=someDefaultValue]` content. Defaults to `false`.

<a name="user-content-processors-options-checkproperties"></a>
<a name="processors-options-checkproperties"></a>
#### <code>checkProperties</code>

Whether to check `@property [name=someDefaultValue]` content. Defaults to `false`.

<a name="user-content-processors-options-captionrequired"></a>
<a name="processors-options-captionrequired"></a>
#### <code>captionRequired</code>

Whether to require the JSDoc `<caption></caption>` content inside the `@example`
tag. Defaults to `false`.

<a name="user-content-processors-options-paddedindent"></a>
<a name="processors-options-paddedindent"></a>
#### <code>paddedIndent</code>

The number of spaces to assume at the beginning of each line. Defaults to 0. Should
only have an effect on whitespace-based rules.

<a name="user-content-processors-options-matchingfilename"></a>
<a name="processors-options-matchingfilename"></a>
#### <code>matchingFileName</code>
<a name="user-content-processors-options-matchingfilenamedefaults"></a>
<a name="processors-options-matchingfilenamedefaults"></a>
#### <code>matchingFileNameDefaults</code>
<a name="user-content-processors-options-matchingfilenameparams"></a>
<a name="processors-options-matchingfilenameparams"></a>
#### <code>matchingFileNameParams</code>
<a name="user-content-processors-options-matchingfilenameproperties"></a>
<a name="processors-options-matchingfilenameproperties"></a>
#### <code>matchingFileNameProperties</code>

See the [`check-examples`](./rules/check-examples.md#readme) option of the
same name.

<a name="user-content-processors-options-examplecoderegex-and-rejectexamplecoderegex"></a>
<a name="processors-options-examplecoderegex-and-rejectexamplecoderegex"></a>
#### <code>exampleCodeRegex</code> and <code>rejectExampleCodeRegex</code>

See the [`check-examples`](./rules/check-examples.md#readme) option of the
same name.

<a name="user-content-processors-options-sourcetype"></a>
<a name="processors-options-sourcetype"></a>
#### <code>sourceType</code>

Whether to use "script" or "module" with the parser. Defaults to `"module"`.

<a name="user-content-processors-options-parser"></a>
<a name="processors-options-parser"></a>
#### <code>parser</code>

An alternative parser which has a `parseForESLint` method and returns the AST
on the `ast` property (like `typescript-eslint`). Defaults to using ESLint's
Espree parser.
4 changes: 2 additions & 2 deletions docs/rules/check-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
* [Passing examples](#user-content-check-examples-passing-examples)


> **NOTE**: This rule currently does not work in ESLint 8 (we are waiting for
> [issue 14745](https://github.com/eslint/eslint/issues/14745)).
> **NOTE**: This rule only works in ESLint 7. For ESLint 9, please see our
> [processors](../processors.md) section.

Ensures that (JavaScript) examples within JSDoc adhere to ESLint rules. Also
has options to lint the default values of optional `@param`/`@arg`/`@argument`
Expand Down
5 changes: 3 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ const common = {
},
plugins: {
jsdoc
}
},
};

export default [
// canonical,
// canonicalJsdoc,
...jsdoc.configs['examples-and-default-expressions'],
{
// Must be by itself
ignores: ['dist/**/*.js', '.ignore/**/*.js'],
ignores: ['dist/**', '.ignore/**/*.js'],
},
{
...common,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@types/chai": "^4.3.16",
"@types/debug": "^4.1.12",
"@types/eslint": "^8.56.10",
"@types/espree": "^10.1.0",
"@types/esquery": "^1.5.4",
"@types/estree": "^1.0.5",
"@types/json-schema": "^7.0.15",
Expand Down
Loading
Loading