Skip to content

Commit aed3194

Browse files
authoredAug 13, 2024··
feat: added granular flat TypeScript configs (#1298)
* feat: added granular flat TypeScript configs --------- Co-authored-by: Brett Zamir <brettz9@yahoo.com> * docs: add rationales section
1 parent 6e82aeb commit aed3194

File tree

3 files changed

+259
-0
lines changed

3 files changed

+259
-0
lines changed
 

‎.README/README.md

+69
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,75 @@ const config = [
5050
export default config;
5151
```
5252

53+
The general starting rulesets you can extend from in flat config are:
54+
55+
- `jsdoc.configs['flat/recommended']`: Recommended starting rules for enforcing proper tag values, that common tags exist, and that tags are formatted and styled consistently
56+
- `jsdoc.configs['flat/recommended-error']`: The same, reporting with failing errors instead of mere warnings
57+
- `jsdoc.configs['flat/recommended-typescript']`: A similar recommended starting list, adjusted for projects using TypeScript syntax (and not just the "typescript" `mode` setting)
58+
- `jsdoc.configs['flat/recommended-typescript-error']`: The same, reporting with failing errors instead of mere warnings
59+
- `jsdoc.configs['flat/recommended-typescript-flavor']`: A similar recommended starting list, adjusted for projects using JavaScript syntax (source files that are still `.js`) but using TypeScript flavor within JSDoc (i.e., the default "typescript" `mode` in `eslint-plugin-jsdoc`)
60+
- `jsdoc.configs['flat/recommended-typescript-flavor-error']`: The same, reporting with failing errors instead of mere warnings
61+
62+
#### Granular Flat Configs
63+
64+
There also exist several more granular, standalone TypeScript rulesets you can extend from.
65+
These each only enable mostly or only rules from the recommended starting rules:
66+
67+
- **Contents**: rules that check names and descriptions
68+
- `jsdoc.configs['flat/contents-typescript']`: for TypeScript files, with reports set to warn
69+
- `jsdoc.configs['flat/contents-typescript-error']`: for TypeScript files, with reports set to error
70+
- `jsdoc.configs['flat/contents-typescript-flavor']`: for files using JavaScript syntax and JSDoc types, with reports set to warn
71+
- `jsdoc.configs['flat/contents-typescript-flavor-error']`: for files using JavaScript syntax and JSDoc types, with reports set to error
72+
- **Logical**: rules that enforce proper tag values
73+
- `jsdoc.configs['flat/logical-typescript']`: for TypeScript files, with reports set to warn
74+
- `jsdoc.configs['flat/logical-typescript-error']`: for TypeScript files, with reports set to error
75+
- `jsdoc.configs['flat/logical-typescript-flavor']`: for files using JavaScript syntax and JSDoc types, with reports set to warn
76+
- `jsdoc.configs['flat/logical-typescript-flavor-error']`: for files using JavaScript syntax and JSDoc types, with reports set to error
77+
- **Requirements**: rules that enforce tags exist
78+
- `jsdoc.configs['flat/requirements-typescript']`: for TypeScript files, with reports set to warn
79+
- `jsdoc.configs['flat/requirements-typescript-error']`: for TypeScript files, with reports set to error
80+
- `jsdoc.configs['flat/requirements-typescript-flavor']`: for files using JavaScript syntax and JSDoc types, with reports set to warn
81+
- `jsdoc.configs['flat/requirements-typescript-flavor-error']`: for files using JavaScript syntax and JSDoc types, with reports set to error
82+
- **Stylistic**: rules that enforce clear, consistent tag formatting and styles
83+
- `jsdoc.configs['flat/stylistic-typescript']`: for TypeScript files, with reports set to warn
84+
- `jsdoc.configs['flat/stylistic-typescript-error']`: for TypeScript files, with reports set to error
85+
- `jsdoc.configs['flat/stylistic-typescript-flavor']`: for files using JavaScript syntax and JSDoc types, with reports set to warn
86+
- `jsdoc.configs['flat/stylistic-typescript-flavor-error']`: for files using JavaScript syntax and JSDoc types, with reports set to error
87+
88+
For example, to enforce only that any JSDoc tags and their contents are valid and styled consistently in TypeScript files, without enforcing that tags must always exist:
89+
90+
```js
91+
import jsdoc from 'eslint-plugin-jsdoc';
92+
93+
export default [
94+
jsdoc.configs['flat/contents-typescript-error'],
95+
jsdoc.configs['flat/logical-typescript-error'],
96+
jsdoc.configs['flat/stylistic-typescript-error'],
97+
];
98+
```
99+
100+
##### Why certain rules were excluded from the granular configs
101+
102+
A few rules were left out of the granular configs. Here is why:
103+
104+
Rules which might have been added to `required`:
105+
- [`require-throws`](./docs/rules/require-throws.md#readme) - Since this can't enforce all cases, some may not wish this rule enforced.
106+
- [`require-file-overview`](./docs/rules/require-file-overview.md#readme) - Too demanding for all projects
107+
- [`convert-to-jsdoc-comments`](./docs/rules/convert-to-jsdoc-comments.md#readme) - Overly aggressive for some projects
108+
109+
Rules which might have been added to `logical`:
110+
- [`no-missing-syntax`](./docs/rules/no-missing-syntax.md#readme) - Has no default options.
111+
- [`no-restricted-syntax`](./docs/rules/no-restricted-syntax.md#readme) - Has no default options.
112+
113+
Rules which might have been added to `contents`:
114+
- [`match-name`](./docs/rules/match-name.md#readme) - Has no default options.
115+
- [`require-description`](./docs/rules/require-description.md#readme) - Too demanding for all projects
116+
- [`require-description-complete-sentence`](./docs/rules/require-description-complete-sentence.md#readme) - Too demanding for all projects
117+
118+
Rules which might have been added to `stylistic`:
119+
- [`check-indentation`](./docs/rules/check-indentation.md#readme) - May not be desired by all projects
120+
- [`sort-tags`](./docs/rules/sort-tags.md#readme) - Too project-specific
121+
53122
### `eslintrc`
54123

55124
Add `plugins` section to [.eslintrc.*](https://eslint.org/docs/user-guide/configuring#configuration-file-formats)

‎README.md

+73
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,79 @@ const config = [
6868
export default config;
6969
```
7070

71+
The general starting rulesets you can extend from in flat config are:
72+
73+
- `jsdoc.configs['flat/recommended']`: Recommended starting rules for enforcing proper tag values, that common tags exist, and that tags are formatted and styled consistently
74+
- `jsdoc.configs['flat/recommended-error']`: The same, reporting with failing errors instead of mere warnings
75+
- `jsdoc.configs['flat/recommended-typescript']`: A similar recommended starting list, adjusted for projects using TypeScript syntax (and not just the "typescript" `mode` setting)
76+
- `jsdoc.configs['flat/recommended-typescript-error']`: The same, reporting with failing errors instead of mere warnings
77+
- `jsdoc.configs['flat/recommended-typescript-flavor']`: A similar recommended starting list, adjusted for projects using JavaScript syntax (source files that are still `.js`) but using TypeScript flavor within JSDoc (i.e., the default "typescript" `mode` in `eslint-plugin-jsdoc`)
78+
- `jsdoc.configs['flat/recommended-typescript-flavor-error']`: The same, reporting with failing errors instead of mere warnings
79+
80+
<a name="user-content-eslint-plugin-jsdoc-configuration-flat-config-granular-flat-configs"></a>
81+
<a name="eslint-plugin-jsdoc-configuration-flat-config-granular-flat-configs"></a>
82+
#### Granular Flat Configs
83+
84+
There also exist several more granular, standalone TypeScript rulesets you can extend from.
85+
These each only enable mostly or only rules from the recommended starting rules:
86+
87+
- **Contents**: rules that check names and descriptions
88+
- `jsdoc.configs['flat/contents-typescript']`: for TypeScript files, with reports set to warn
89+
- `jsdoc.configs['flat/contents-typescript-error']`: for TypeScript files, with reports set to error
90+
- `jsdoc.configs['flat/contents-typescript-flavor']`: for files using JavaScript syntax and JSDoc types, with reports set to warn
91+
- `jsdoc.configs['flat/contents-typescript-flavor-error']`: for files using JavaScript syntax and JSDoc types, with reports set to error
92+
- **Logical**: rules that enforce proper tag values
93+
- `jsdoc.configs['flat/logical-typescript']`: for TypeScript files, with reports set to warn
94+
- `jsdoc.configs['flat/logical-typescript-error']`: for TypeScript files, with reports set to error
95+
- `jsdoc.configs['flat/logical-typescript-flavor']`: for files using JavaScript syntax and JSDoc types, with reports set to warn
96+
- `jsdoc.configs['flat/logical-typescript-flavor-error']`: for files using JavaScript syntax and JSDoc types, with reports set to error
97+
- **Requirements**: rules that enforce tags exist
98+
- `jsdoc.configs['flat/requirements-typescript']`: for TypeScript files, with reports set to warn
99+
- `jsdoc.configs['flat/requirements-typescript-error']`: for TypeScript files, with reports set to error
100+
- `jsdoc.configs['flat/requirements-typescript-flavor']`: for files using JavaScript syntax and JSDoc types, with reports set to warn
101+
- `jsdoc.configs['flat/requirements-typescript-flavor-error']`: for files using JavaScript syntax and JSDoc types, with reports set to error
102+
- **Stylistic**: rules that enforce clear, consistent tag formatting and styles
103+
- `jsdoc.configs['flat/stylistic-typescript']`: for TypeScript files, with reports set to warn
104+
- `jsdoc.configs['flat/stylistic-typescript-error']`: for TypeScript files, with reports set to error
105+
- `jsdoc.configs['flat/stylistic-typescript-flavor']`: for files using JavaScript syntax and JSDoc types, with reports set to warn
106+
- `jsdoc.configs['flat/stylistic-typescript-flavor-error']`: for files using JavaScript syntax and JSDoc types, with reports set to error
107+
108+
For example, to enforce only that any JSDoc tags and their contents are valid and styled consistently in TypeScript files, without enforcing that tags must always exist:
109+
110+
```js
111+
import jsdoc from 'eslint-plugin-jsdoc';
112+
113+
export default [
114+
jsdoc.configs['flat/contents-typescript-error'],
115+
jsdoc.configs['flat/logical-typescript-error'],
116+
jsdoc.configs['flat/stylistic-typescript-error'],
117+
];
118+
```
119+
120+
<a name="user-content-eslint-plugin-jsdoc-configuration-flat-config-granular-flat-configs-why-certain-rules-were-excluded-from-the-granular-configs"></a>
121+
<a name="eslint-plugin-jsdoc-configuration-flat-config-granular-flat-configs-why-certain-rules-were-excluded-from-the-granular-configs"></a>
122+
##### Why certain rules were excluded from the granular configs
123+
124+
A few rules were left out of the granular configs. Here is why:
125+
126+
Rules which might have been added to `required`:
127+
- [`require-throws`](./docs/rules/require-throws.md#readme) - Since this can't enforce all cases, some may not wish this rule enforced.
128+
- [`require-file-overview`](./docs/rules/require-file-overview.md#readme) - Too demanding for all projects
129+
- [`convert-to-jsdoc-comments`](./docs/rules/convert-to-jsdoc-comments.md#readme) - Overly aggressive for some projects
130+
131+
Rules which might have been added to `logical`:
132+
- [`no-missing-syntax`](./docs/rules/no-missing-syntax.md#readme) - Has no default options.
133+
- [`no-restricted-syntax`](./docs/rules/no-restricted-syntax.md#readme) - Has no default options.
134+
135+
Rules which might have been added to `contents`:
136+
- [`match-name`](./docs/rules/match-name.md#readme) - Has no default options.
137+
- [`require-description`](./docs/rules/require-description.md#readme) - Too demanding for all projects
138+
- [`require-description-complete-sentence`](./docs/rules/require-description-complete-sentence.md#readme) - Too demanding for all projects
139+
140+
Rules which might have been added to `stylistic`:
141+
- [`check-indentation`](./docs/rules/check-indentation.md#readme) - May not be desired by all projects
142+
- [`sort-tags`](./docs/rules/sort-tags.md#readme) - Too project-specific
143+
71144
<a name="user-content-eslint-plugin-jsdoc-configuration-eslintrc"></a>
72145
<a name="eslint-plugin-jsdoc-configuration-eslintrc"></a>
73146
### <code>eslintrc</code>

‎src/index.js

+117
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,106 @@ const createRecommendedTypeScriptFlavorRuleset = (warnOrError, flatName) => {
260260
};
261261
};
262262

263+
/**
264+
* @param {(string | unknown[])[]} ruleNames
265+
*/
266+
const createStandaloneRulesetFactory = (ruleNames) => {
267+
/**
268+
* @param {"warn"|"error"} warnOrError
269+
* @param {string} [flatName]
270+
* @returns {import('eslint').Linter.FlatConfig}
271+
*/
272+
return (warnOrError, flatName) => {
273+
return {
274+
name: 'jsdoc/' + flatName,
275+
plugins: { jsdoc: index },
276+
rules: Object.fromEntries(
277+
ruleNames.map(
278+
ruleName =>
279+
typeof ruleName === "string"
280+
? [ruleName, warnOrError]
281+
: [ruleName[0], warnOrError, ...ruleName.slice(1)]
282+
)
283+
),
284+
};
285+
};
286+
}
287+
288+
const contentsRules = [
289+
'jsdoc/informative-docs',
290+
'jsdoc/match-description',
291+
'jsdoc/no-blank-block-descriptions',
292+
'jsdoc/no-blank-blocks',
293+
['jsdoc/text-escaping', { escapeHTML: true }]
294+
]
295+
296+
const createContentsTypescriptRuleset = createStandaloneRulesetFactory(contentsRules);
297+
298+
const createContentsTypescriptFlavorRuleset = createStandaloneRulesetFactory(contentsRules);
299+
300+
const logicalRules = [
301+
'jsdoc/check-access',
302+
'jsdoc/check-param-names',
303+
'jsdoc/check-property-names',
304+
'jsdoc/check-syntax',
305+
'jsdoc/check-tag-names',
306+
'jsdoc/check-template-names',
307+
'jsdoc/check-types',
308+
'jsdoc/check-values',
309+
'jsdoc/empty-tags',
310+
'jsdoc/implements-on-classes',
311+
'jsdoc/require-returns-check',
312+
'jsdoc/require-yields-check',
313+
'jsdoc/no-bad-blocks',
314+
'jsdoc/no-defaults',
315+
'jsdoc/no-types',
316+
'jsdoc/no-undefined-types',
317+
'jsdoc/valid-types',
318+
];
319+
320+
const createLogicalTypescriptRuleset = createStandaloneRulesetFactory(logicalRules);
321+
322+
const createLogicalTypescriptFlavorRuleset = createStandaloneRulesetFactory(logicalRules);
323+
324+
const requirementsRules = [
325+
'jsdoc/require-example',
326+
'jsdoc/require-jsdoc',
327+
'jsdoc/require-param',
328+
'jsdoc/require-param-description',
329+
'jsdoc/require-param-name',
330+
'jsdoc/require-property',
331+
'jsdoc/require-property-description',
332+
'jsdoc/require-property-name',
333+
'jsdoc/require-returns',
334+
'jsdoc/require-returns-description',
335+
'jsdoc/require-yields',
336+
];
337+
338+
const createRequirementsTypeScriptRuleset = createStandaloneRulesetFactory(requirementsRules);
339+
340+
const createRequirementsTypeScriptFlavorRuleset = createStandaloneRulesetFactory([
341+
...requirementsRules,
342+
'jsdoc/require-param-type',
343+
'jsdoc/require-property-type',
344+
'jsdoc/require-returns-type',
345+
'jsdoc/require-template',
346+
]);
347+
348+
const stylisticRules = [
349+
'jsdoc/check-alignment',
350+
'jsdoc/check-line-alignment',
351+
'jsdoc/lines-before-block',
352+
'jsdoc/multiline-blocks',
353+
'jsdoc/no-multi-asterisks',
354+
'jsdoc/require-asterisk-prefix',
355+
['jsdoc/require-hyphen-before-param-description', 'never'],
356+
'jsdoc/tag-lines',
357+
];
358+
359+
const createStylisticTypeScriptRuleset = createStandaloneRulesetFactory(stylisticRules);
360+
361+
const createStylisticTypeScriptFlavorRuleset = createStandaloneRulesetFactory(stylisticRules);
362+
263363
/* c8 ignore next 3 -- TS */
264364
if (!index.configs) {
265365
throw new Error('TypeScript guard');
@@ -279,6 +379,23 @@ index.configs['flat/recommended-typescript-error'] = createRecommendedTypeScript
279379
index.configs['flat/recommended-typescript-flavor'] = createRecommendedTypeScriptFlavorRuleset('warn', 'flat/recommended-typescript-flavor');
280380
index.configs['flat/recommended-typescript-flavor-error'] = createRecommendedTypeScriptFlavorRuleset('error', 'flat/recommended-typescript-flavor-error');
281381

382+
index.configs['flat/contents-typescript'] = createContentsTypescriptRuleset('warn', 'flat/contents-typescript');
383+
index.configs['flat/contents-typescript-error'] = createContentsTypescriptRuleset('error', 'flat/contents-typescript-error');
384+
index.configs['flat/contents-typescript-flavor'] = createContentsTypescriptFlavorRuleset('warn', 'flat/contents-typescript-flavor');
385+
index.configs['flat/contents-typescript-flavor-error'] = createContentsTypescriptFlavorRuleset('error', 'flat/contents-typescript-error-flavor');
386+
index.configs['flat/logical-typescript'] = createLogicalTypescriptRuleset('warn', 'flat/logical-typescript');
387+
index.configs['flat/logical-typescript-error'] = createLogicalTypescriptRuleset('error', 'flat/logical-typescript-error');
388+
index.configs['flat/logical-typescript-flavor'] = createLogicalTypescriptFlavorRuleset('warn', 'flat/logical-typescript-flavor');
389+
index.configs['flat/logical-typescript-flavor-error'] = createLogicalTypescriptFlavorRuleset('error', 'flat/logical-typescript-error-flavor');
390+
index.configs['flat/requirements-typescript'] = createRequirementsTypeScriptRuleset('warn', 'flat/requirements-typescript');
391+
index.configs['flat/requirements-typescript-error'] = createRequirementsTypeScriptRuleset('error', 'flat/requirements-typescript-error');
392+
index.configs['flat/requirements-typescript-flavor'] = createRequirementsTypeScriptFlavorRuleset('warn', 'flat/requirements-typescript-flavor');
393+
index.configs['flat/requirements-typescript-flavor-error'] = createRequirementsTypeScriptFlavorRuleset('error', 'flat/requirements-typescript-error-flavor');
394+
index.configs['flat/stylistic-typescript'] = createStylisticTypeScriptRuleset('warn', 'flat/stylistic-typescript');
395+
index.configs['flat/stylistic-typescript-error'] = createStylisticTypeScriptRuleset('error', 'flat/stylistic-typescript-error');
396+
index.configs['flat/stylistic-typescript-flavor'] = createStylisticTypeScriptFlavorRuleset('warn', 'flat/stylistic-typescript-flavor');
397+
index.configs['flat/stylistic-typescript-flavor-error'] = createStylisticTypeScriptFlavorRuleset('error', 'flat/stylistic-typescript-error-flavor');
398+
282399
index.configs.examples = /** @type {import('eslint').Linter.FlatConfig[]} */ ([
283400
{
284401
name: 'jsdoc/examples/processor',

0 commit comments

Comments
 (0)
Please sign in to comment.