Skip to content

Commit 0a047d5

Browse files
committed
feat(plugin-jsdocs): add setup wizard binding
1 parent 3d440fa commit 0a047d5

5 files changed

Lines changed: 186 additions & 1 deletion

File tree

‎packages/create-cli/README.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ Each plugin exposes its own configuration keys that can be passed as CLI argumen
7272
|**`--lighthouse.urls`**|`string \| string[]`|`http://localhost:4200`| Target URL(s) (comma-separated) |
7373
|**`--lighthouse.categories`**|`('performance'`\|`'a11y'`\|`'best-practices'`\|`'seo')[]`| all | Lighthouse categories |
7474

75+
#### JSDocs
76+
77+
| Option | Type | Default | Description |
78+
| ------------------------- | -------------------- | -------------------------------------------- | -------------------------------------- |
79+
|**`--jsdocs.patterns`**|`string \| string[]`|`src/**/*.ts, src/**/*.js, !**/node_modules`| Source file patterns (comma-separated) |
80+
|**`--jsdocs.categories`**|`boolean`|`true`| Add JSDocs categories |
81+
7582
#### Axe
7683

7784
| Option | Type | Default | Description |

‎packages/create-cli/src/index.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { axeSetupBinding } from '@code-pushup/axe-plugin';
55
import{coverageSetupBinding}from'@code-pushup/coverage-plugin';
66
import{eslintSetupBinding}from'@code-pushup/eslint-plugin';
77
import{jsPackagesSetupBinding}from'@code-pushup/js-packages-plugin';
8+
import{jsDocsSetupBinding}from'@code-pushup/jsdocs-plugin';
89
import{lighthouseSetupBinding}from'@code-pushup/lighthouse-plugin';
910
import{typescriptSetupBinding}from'@code-pushup/typescript-plugin';
1011
import{parsePluginSlugs,validatePluginSlugs}from'./lib/setup/plugins.js';
@@ -16,14 +17,14 @@ import {
1617
}from'./lib/setup/types.js';
1718
import{runSetupWizard}from'./lib/setup/wizard.js';
1819

19-
// TODO: create, import and pass remaining plugin bindings (jsdocs)
2020
constbindings: PluginSetupBinding[]=[
2121
eslintSetupBinding,
2222
coverageSetupBinding,
2323
jsPackagesSetupBinding,
2424
typescriptSetupBinding,
2525
lighthouseSetupBinding,
2626
axeSetupBinding,
27+
jsDocsSetupBinding,
2728
];
2829

2930
constargv=awaityargs(hideBin(process.argv))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import{jsDocsPlugin}from'./lib/jsdocs-plugin.js';
22

33
exportdefaultjsDocsPlugin;
4+
export{jsDocsSetupBinding}from'./lib/binding.js';
45
exporttype{JsDocsPluginConfig}from'./lib/config.js';
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import{createRequire}from'node:module';
2+
importtype{
3+
CategoryConfig,
4+
PluginAnswer,
5+
PluginSetupBinding,
6+
}from'@code-pushup/models';
7+
import{
8+
answerBoolean,
9+
answerNonEmptyArray,
10+
singleQuote,
11+
}from'@code-pushup/utils';
12+
import{PLUGIN_SLUG,PLUGIN_TITLE}from'./constants.js';
13+
14+
const{name: PACKAGE_NAME}=createRequire(import.meta.url)(
15+
'../../package.json',
16+
)astypeofimport('../../package.json');
17+
18+
constDEFAULT_PATTERNS: [string, ...string[]]=[
19+
'src/**/*.ts',
20+
'src/**/*.js',
21+
'!**/node_modules',
22+
];
23+
24+
constCATEGORY: CategoryConfig={
25+
slug: 'docs',
26+
title: 'Documentation',
27+
description: 'Measures how much of your code is **documented**.',
28+
refs: [
29+
{
30+
type: 'group',
31+
plugin: PLUGIN_SLUG,
32+
slug: 'documentation-coverage',
33+
weight: 1,
34+
},
35+
],
36+
};
37+
38+
typeJsDocsOptions={
39+
patterns: [string, ...string[]];
40+
categories: boolean;
41+
};
42+
43+
exportconstjsDocsSetupBinding={
44+
slug: PLUGIN_SLUG,
45+
title: PLUGIN_TITLE,
46+
packageName: PACKAGE_NAME,
47+
prompts: async()=>[
48+
{
49+
key: 'jsdocs.patterns',
50+
message: 'Source file patterns (comma-separated)',
51+
type: 'input',
52+
default: DEFAULT_PATTERNS.join(', '),
53+
},
54+
{
55+
key: 'jsdocs.categories',
56+
message: 'Add JSDocs categories?',
57+
type: 'confirm',
58+
default: true,
59+
},
60+
],
61+
generateConfig: (answers: Record<string,PluginAnswer>)=>{
62+
constoptions=parseAnswers(answers);
63+
return{
64+
imports: [
65+
{moduleSpecifier: PACKAGE_NAME,defaultImport: 'jsDocsPlugin'},
66+
],
67+
pluginInit: formatPluginInit(options.patterns),
68+
...(options.categories ? {categories: [CATEGORY]} : {}),
69+
};
70+
},
71+
}satisfiesPluginSetupBinding;
72+
73+
functionparseAnswers(answers: Record<string,PluginAnswer>): JsDocsOptions{
74+
return{
75+
patterns: answerNonEmptyArray(
76+
answers,
77+
'jsdocs.patterns',
78+
DEFAULT_PATTERNS[0],
79+
),
80+
categories: answerBoolean(answers,'jsdocs.categories'),
81+
};
82+
}
83+
84+
functionformatPluginInit([first, ...rest]: [string, ...string[]]): string[]{
85+
if(rest.length===0){
86+
return[`jsDocsPlugin(${singleQuote(first)}),`];
87+
}
88+
return[
89+
'jsDocsPlugin([',
90+
...[first, ...rest].map(p=>` ${singleQuote(p)},`),
91+
']),',
92+
];
93+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
importtype{PluginAnswer}from'@code-pushup/models';
2+
import{jsDocsSetupBindingasbinding}from'./binding.js';
3+
4+
constdefaultAnswers: Record<string,PluginAnswer>={
5+
'jsdocs.patterns': 'src/**/*.ts, src/**/*.js, !**/node_modules',
6+
'jsdocs.categories': true,
7+
};
8+
9+
constnoCategoryAnswers: Record<string,PluginAnswer>={
10+
...defaultAnswers,
11+
'jsdocs.categories': false,
12+
};
13+
14+
describe('jsDocsSetupBinding',()=>{
15+
describe('prompts',()=>{
16+
it('should default to common TypeScript and JavaScript source patterns',async()=>{
17+
awaitexpect(binding.prompts!()).resolves.toIncludeAllPartialMembers([
18+
{
19+
key: 'jsdocs.patterns',
20+
type: 'input',
21+
default: 'src/**/*.ts, src/**/*.js, !**/node_modules',
22+
},
23+
]);
24+
});
25+
26+
it('should offer to add categories by default',async()=>{
27+
awaitexpect(binding.prompts!()).resolves.toIncludeAllPartialMembers([
28+
{key: 'jsdocs.categories',type: 'confirm',default: true},
29+
]);
30+
});
31+
});
32+
33+
describe('generateConfig',()=>{
34+
it('should import from @code-pushup/jsdocs-plugin',()=>{
35+
const{ imports }=binding.generateConfig(defaultAnswers);
36+
expect(imports).toStrictEqual([
37+
expect.objectContaining({
38+
defaultImport: 'jsDocsPlugin',
39+
}),
40+
]);
41+
});
42+
43+
it('should pass multiple patterns as array to plugin call',()=>{
44+
const{ pluginInit }=binding.generateConfig(defaultAnswers);
45+
expect(pluginInit).toStrictEqual([
46+
'jsDocsPlugin([',
47+
" 'src/**/*.ts',",
48+
" 'src/**/*.js',",
49+
" '!**/node_modules',",
50+
']),',
51+
]);
52+
});
53+
54+
it('should pass single pattern as string to plugin call',()=>{
55+
const{ pluginInit }=binding.generateConfig({
56+
...defaultAnswers,
57+
'jsdocs.patterns': 'src/**/*.ts',
58+
});
59+
expect(pluginInit).toStrictEqual(["jsDocsPlugin('src/**/*.ts'),"]);
60+
});
61+
62+
it('should generate Documentation category from documentation-coverage group',()=>{
63+
const{ categories }=binding.generateConfig(defaultAnswers);
64+
expect(categories).toStrictEqual([
65+
expect.objectContaining({
66+
slug: 'docs',
67+
title: 'Documentation',
68+
refs: [
69+
expect.objectContaining({
70+
plugin: 'jsdocs',
71+
slug: 'documentation-coverage',
72+
}),
73+
],
74+
}),
75+
]);
76+
});
77+
78+
it('should omit categories when declined',()=>{
79+
const{ categories }=binding.generateConfig(noCategoryAnswers);
80+
expect(categories).toBeUndefined();
81+
});
82+
});
83+
});

0 commit comments

Comments
 (0)