Skip to content

Commit 9c92842

Browse files
authored
Support multiple potential property locations for config description (#508)
1 parent 6307e8b commit 9c92842

File tree

4 files changed

+198
-45
lines changed

4 files changed

+198
-45
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Delete any old rules list from your `README.md`. A new one will be automatically
8787
<!-- end auto-generated rules list -->
8888
```
8989

90-
Optionally, add these marker comments to your `README.md` in a `## Configs` section or similar location (uses the `description` property exported by each config if available):
90+
Optionally, add these marker comments to your `README.md` in a `## Configs` section or similar location (uses the `meta.docs.description` property exported by each config if available):
9191

9292
```md
9393
<!-- begin auto-generated configs list -->

lib/config-list.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,31 @@ import {
33
END_CONFIG_LIST_MARKER,
44
} from './comment-markers.js';
55
import { markdownTable } from 'markdown-table';
6-
import type { ConfigsToRules, ConfigEmojis, Plugin } from './types.js';
6+
import type { ConfigsToRules, ConfigEmojis, Plugin, Config } from './types.js';
77
import { ConfigFormat, configNameToDisplay } from './config-format.js';
88
import { sanitizeMarkdownTable } from './string.js';
99

10+
/**
11+
* Check potential locations for the config description.
12+
* These are not official properties.
13+
* The recommended/allowed way to add a description is still pending the outcome of: https://github.com/eslint/eslint/issues/17842
14+
* @param config
15+
* @returns the description if available
16+
*/
17+
function configToDescription(config: Config): string | undefined {
18+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
19+
return (
20+
// @ts-expect-error -- description is not an official config property.
21+
config.description ||
22+
// @ts-expect-error -- description is not an official config property.
23+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
24+
config.meta?.description ||
25+
// @ts-expect-error -- description is not an official config property.
26+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
27+
config.meta?.docs?.description
28+
);
29+
}
30+
1031
function generateConfigListMarkdown(
1132
plugin: Plugin,
1233
configsToRules: ConfigsToRules,
@@ -17,10 +38,7 @@ function generateConfigListMarkdown(
1738
): string {
1839
/* istanbul ignore next -- configs are sure to exist at this point */
1940
const configs = Object.values(plugin.configs || {});
20-
const hasDescription = configs.some(
21-
// @ts-expect-error -- description is not an official config property.
22-
(config) => config.description
23-
);
41+
const hasDescription = configs.some((config) => configToDescription(config));
2442
const listHeaderRow = ['', 'Name'];
2543
if (hasDescription) {
2644
listHeaderRow.push('Description');
@@ -33,8 +51,9 @@ function generateConfigListMarkdown(
3351
.filter((configName) => !ignoreConfig.includes(configName))
3452
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
3553
.map((configName) => {
36-
const description = // @ts-expect-error -- description is not an official config property.
37-
plugin.configs?.[configName]?.description as string | undefined;
54+
const config = plugin.configs?.[configName];
55+
/* istanbul ignore next -- config should exist at this point */
56+
const description = config ? configToDescription(config) : undefined;
3857
return [
3958
configEmojis.find((obj) => obj.config === configName)?.emoji || '',
4059
`\`${configNameToDisplay(

test/lib/generate/__snapshots__/configs-list-test.ts.snap

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ exports[`generate (configs list) when a config description needs to be escaped i
3838
<!-- end auto-generated configs list -->"
3939
`;
4040

41-
exports[`generate (configs list) when a config exports a description generates the documentation 1`] = `
41+
exports[`generate (configs list) when a config exports a description property=description generates the documentation 1`] = `
4242
"## Rules
4343
<!-- begin auto-generated rules list -->
4444
@@ -47,8 +47,48 @@ exports[`generate (configs list) when a config exports a description generates t
4747
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. |
4848
4949
<!-- end auto-generated rules list -->
50-
## Configs
51-
<!-- begin auto-generated configs list -->
50+
## Configs
51+
<!-- begin auto-generated configs list -->
52+
53+
| | Name | Description |
54+
| :- | :------------ | :--------------------------------------- |
55+
| | \`foo\` | |
56+
| ✅ | \`recommended\` | This config has the recommended rules... |
57+
58+
<!-- end auto-generated configs list -->"
59+
`;
60+
61+
exports[`generate (configs list) when a config exports a description property=meta.description generates the documentation 1`] = `
62+
"## Rules
63+
<!-- begin auto-generated rules list -->
64+
65+
| Name | Description |
66+
| :----------------------------- | :--------------------- |
67+
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. |
68+
69+
<!-- end auto-generated rules list -->
70+
## Configs
71+
<!-- begin auto-generated configs list -->
72+
73+
| | Name | Description |
74+
| :- | :------------ | :--------------------------------------- |
75+
| | \`foo\` | |
76+
| ✅ | \`recommended\` | This config has the recommended rules... |
77+
78+
<!-- end auto-generated configs list -->"
79+
`;
80+
81+
exports[`generate (configs list) when a config exports a description property=meta.docs.description generates the documentation 1`] = `
82+
"## Rules
83+
<!-- begin auto-generated rules list -->
84+
85+
| Name | Description |
86+
| :----------------------------- | :--------------------- |
87+
| [no-foo](docs/rules/no-foo.md) | Description of no-foo. |
88+
89+
<!-- end auto-generated rules list -->
90+
## Configs
91+
<!-- begin auto-generated configs list -->
5292
5393
| | Name | Description |
5494
| :- | :------------ | :--------------------------------------- |

test/lib/generate/configs-list-test.ts

Lines changed: 128 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -193,48 +193,142 @@ describe('generate (configs list)', function () {
193193
});
194194

195195
describe('when a config exports a description', function () {
196-
beforeEach(function () {
197-
mockFs({
198-
'package.json': JSON.stringify({
199-
name: 'eslint-plugin-test',
200-
exports: 'index.js',
201-
type: 'module',
202-
}),
203-
204-
'index.js': `
205-
export default {
206-
rules: {
207-
'no-foo': {
208-
meta: { docs: { description: 'Description of no-foo.' }, },
209-
create(context) {}
196+
describe('property=description', function () {
197+
beforeEach(function () {
198+
mockFs({
199+
'package.json': JSON.stringify({
200+
name: 'eslint-plugin-test',
201+
exports: 'index.js',
202+
type: 'module',
203+
}),
204+
205+
'index.js': `
206+
export default {
207+
rules: {
208+
'no-foo': {
209+
meta: { docs: { description: 'Description of no-foo.' }, },
210+
create(context) {}
211+
},
210212
},
211-
},
212-
configs: {
213-
foo: {},
214-
recommended: { description: 'This config has the recommended rules...' },
215-
}
216-
};`,
217-
218-
'README.md': `## Rules
219-
## Configs
220-
<!-- begin auto-generated configs list -->
221-
<!-- end auto-generated configs list -->`,
213+
configs: {
214+
foo: {},
215+
recommended: { description: 'This config has the recommended rules...' },
216+
}
217+
};`,
218+
219+
'README.md': `## Rules
220+
## Configs
221+
<!-- begin auto-generated configs list -->
222+
<!-- end auto-generated configs list -->`,
223+
224+
'docs/rules/no-foo.md': '',
225+
226+
// Needed for some of the test infrastructure to work.
227+
node_modules: mockFs.load(PATH_NODE_MODULES),
228+
});
229+
});
222230

223-
'docs/rules/no-foo.md': '',
231+
afterEach(function () {
232+
mockFs.restore();
233+
jest.resetModules();
234+
});
224235

225-
// Needed for some of the test infrastructure to work.
226-
node_modules: mockFs.load(PATH_NODE_MODULES),
236+
it('generates the documentation', async function () {
237+
await generate('.');
238+
expect(readFileSync('README.md', 'utf8')).toMatchSnapshot();
227239
});
228240
});
229241

230-
afterEach(function () {
231-
mockFs.restore();
232-
jest.resetModules();
242+
describe('property=meta.description', function () {
243+
beforeEach(function () {
244+
mockFs({
245+
'package.json': JSON.stringify({
246+
name: 'eslint-plugin-test',
247+
exports: 'index.js',
248+
type: 'module',
249+
}),
250+
251+
'index.js': `
252+
export default {
253+
rules: {
254+
'no-foo': {
255+
meta: { docs: { description: 'Description of no-foo.' }, },
256+
create(context) {}
257+
},
258+
},
259+
configs: {
260+
foo: {},
261+
recommended: { meta: { description: 'This config has the recommended rules...' } },
262+
}
263+
};`,
264+
265+
'README.md': `## Rules
266+
## Configs
267+
<!-- begin auto-generated configs list -->
268+
<!-- end auto-generated configs list -->`,
269+
270+
'docs/rules/no-foo.md': '',
271+
272+
// Needed for some of the test infrastructure to work.
273+
node_modules: mockFs.load(PATH_NODE_MODULES),
274+
});
275+
});
276+
277+
afterEach(function () {
278+
mockFs.restore();
279+
jest.resetModules();
280+
});
281+
282+
it('generates the documentation', async function () {
283+
await generate('.');
284+
expect(readFileSync('README.md', 'utf8')).toMatchSnapshot();
285+
});
233286
});
234287

235-
it('generates the documentation', async function () {
236-
await generate('.');
237-
expect(readFileSync('README.md', 'utf8')).toMatchSnapshot();
288+
describe('property=meta.docs.description', function () {
289+
beforeEach(function () {
290+
mockFs({
291+
'package.json': JSON.stringify({
292+
name: 'eslint-plugin-test',
293+
exports: 'index.js',
294+
type: 'module',
295+
}),
296+
297+
'index.js': `
298+
export default {
299+
rules: {
300+
'no-foo': {
301+
meta: { docs: { description: 'Description of no-foo.' }, },
302+
create(context) {}
303+
},
304+
},
305+
configs: {
306+
foo: {},
307+
recommended: { meta: { docs: { description: 'This config has the recommended rules...' } } },
308+
}
309+
};`,
310+
311+
'README.md': `## Rules
312+
## Configs
313+
<!-- begin auto-generated configs list -->
314+
<!-- end auto-generated configs list -->`,
315+
316+
'docs/rules/no-foo.md': '',
317+
318+
// Needed for some of the test infrastructure to work.
319+
node_modules: mockFs.load(PATH_NODE_MODULES),
320+
});
321+
});
322+
323+
afterEach(function () {
324+
mockFs.restore();
325+
jest.resetModules();
326+
});
327+
328+
it('generates the documentation', async function () {
329+
await generate('.');
330+
expect(readFileSync('README.md', 'utf8')).toMatchSnapshot();
331+
});
238332
});
239333
});
240334

0 commit comments

Comments
 (0)