js-style-kit 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/index.d.ts +11 -5
- package/dist/index.js +48 -7
- package/dist/index.js.map +1 -1
- package/package.json +8 -5
- package/src/eslint/base/README.md +186 -0
- package/src/eslint/base/config.ts +37 -0
- package/src/eslint/base/rules.ts +444 -0
- package/src/eslint/base/types.ts +20 -0
- package/src/eslint/constants.ts +52 -0
- package/src/eslint/convex/README.md +30 -0
- package/src/eslint/convex/config.ts +34 -0
- package/src/eslint/convex/rules.ts +8 -0
- package/src/eslint/convex/types.ts +8 -0
- package/src/eslint/ignores.ts +31 -0
- package/src/eslint/import/README.md +397 -0
- package/src/eslint/import/config.ts +48 -0
- package/src/eslint/import/rules.ts +81 -0
- package/src/eslint/index.ts +259 -0
- package/src/eslint/jsdoc/README.md +399 -0
- package/src/eslint/jsdoc/config.ts +29 -0
- package/src/eslint/jsdoc/rules.ts +81 -0
- package/src/eslint/jsdoc/types.ts +56 -0
- package/src/eslint/nextjs/config.ts +25 -0
- package/src/eslint/nextjs/rules.ts +25 -0
- package/src/eslint/nextjs/types.ts +27 -0
- package/src/eslint/perfectionist/README.md +454 -0
- package/src/eslint/perfectionist/config.ts +25 -0
- package/src/eslint/perfectionist/rules.ts +39 -0
- package/src/eslint/prefer-arrow-function/config.ts +33 -0
- package/src/eslint/prefer-arrow-function/types.ts +13 -0
- package/src/eslint/process-custom-rules.ts +72 -0
- package/src/eslint/query/README.md +254 -0
- package/src/eslint/query/config.ts +27 -0
- package/src/eslint/query/rules.ts +11 -0
- package/src/eslint/query/types.ts +11 -0
- package/src/eslint/react/README.md +416 -0
- package/src/eslint/react/config.ts +65 -0
- package/src/eslint/react/rules.ts +188 -0
- package/src/eslint/react/types.ts +26 -0
- package/src/eslint/react-refresh/config.ts +28 -0
- package/src/eslint/react-refresh/rules.ts +48 -0
- package/src/eslint/storybook/README.md +424 -0
- package/src/eslint/storybook/config.ts +57 -0
- package/src/eslint/testing/README.md +436 -0
- package/src/eslint/testing/config.ts +90 -0
- package/src/eslint/testing/jest-rules.ts +47 -0
- package/src/eslint/testing/vitest-rules.ts +42 -0
- package/src/eslint/turbo/README.md +380 -0
- package/src/eslint/turbo/config.ts +26 -0
- package/src/eslint/turbo/types.ts +7 -0
- package/src/eslint/types.ts +29 -0
- package/src/eslint/typescript/README.md +229 -0
- package/src/eslint/typescript/config.ts +48 -0
- package/src/eslint/typescript/rules.ts +137 -0
- package/src/eslint/typescript/types.ts +35 -0
- package/src/eslint/unicorn/README.md +497 -0
- package/src/eslint/unicorn/config.ts +36 -0
- package/src/eslint/unicorn/rules.ts +86 -0
- package/src/index.ts +3 -0
- package/src/modules.d.ts +5 -0
- package/src/prettier/README.md +413 -0
- package/src/prettier/index.ts +110 -0
- package/src/utils/is-type.ts +60 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import type { Linter } from "eslint";
|
|
2
|
+
|
|
3
|
+
import type { EslintRuleConfig, FilenameCase, FunctionStyle } from "./types.js";
|
|
4
|
+
|
|
5
|
+
import { isObject, isString } from "../utils/is-type.js";
|
|
6
|
+
import { baseEslintConfig } from "./base/config.js";
|
|
7
|
+
import { configNames } from "./constants.js";
|
|
8
|
+
import { convexConfig } from "./convex/config.js";
|
|
9
|
+
import { ignoresConfig } from "./ignores.js";
|
|
10
|
+
import { importConfig } from "./import/config.js";
|
|
11
|
+
import { jsdocConfig } from "./jsdoc/config.js";
|
|
12
|
+
import { nextjsConfig } from "./nextjs/config.js";
|
|
13
|
+
import { perfectionistConfig } from "./perfectionist/config.js";
|
|
14
|
+
import { preferArrowFunctionConfig } from "./prefer-arrow-function/config.js";
|
|
15
|
+
import { processCustomRules } from "./process-custom-rules.js";
|
|
16
|
+
import { queryConfig } from "./query/config.js";
|
|
17
|
+
import { reactRefreshEslintConfig } from "./react-refresh/config.js";
|
|
18
|
+
import { reactEslintConfig } from "./react/config.js";
|
|
19
|
+
import { storybookConfig } from "./storybook/config.js";
|
|
20
|
+
import { testingConfig, type TestingConfig } from "./testing/config.js";
|
|
21
|
+
import { turboConfig } from "./turbo/config.js";
|
|
22
|
+
import { tseslintConfig } from "./typescript/config.js";
|
|
23
|
+
import { unicornConfig } from "./unicorn/config.js";
|
|
24
|
+
|
|
25
|
+
const defaultTestingConfig: TestingConfig = {
|
|
26
|
+
filenamePattern: "test",
|
|
27
|
+
files: ["**/*.{test,spec}.{ts,tsx,js,jsx}"],
|
|
28
|
+
formattingRules: true,
|
|
29
|
+
framework: "vitest",
|
|
30
|
+
itOrTest: "it",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export interface EslintConfigOptions {
|
|
34
|
+
convex?: boolean;
|
|
35
|
+
functionStyle?: "off" | FunctionStyle;
|
|
36
|
+
ignores?: string[];
|
|
37
|
+
importPlugin?: boolean;
|
|
38
|
+
jsdoc?:
|
|
39
|
+
| false
|
|
40
|
+
| {
|
|
41
|
+
requireJsdoc?: boolean;
|
|
42
|
+
};
|
|
43
|
+
query?: boolean;
|
|
44
|
+
react?:
|
|
45
|
+
| boolean
|
|
46
|
+
| {
|
|
47
|
+
framework?: "next" | "none" | "react-router" | "remix" | "vite";
|
|
48
|
+
reactCompiler?: boolean;
|
|
49
|
+
reactRefresh?: boolean;
|
|
50
|
+
};
|
|
51
|
+
rules?: Record<string, EslintRuleConfig>;
|
|
52
|
+
sorting?: boolean;
|
|
53
|
+
storybook?: boolean;
|
|
54
|
+
testing?: false | TestingConfig;
|
|
55
|
+
turbo?: boolean;
|
|
56
|
+
typescript?: boolean | string;
|
|
57
|
+
unicorn?:
|
|
58
|
+
| boolean
|
|
59
|
+
| {
|
|
60
|
+
filenameCase?: FilenameCase;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Configures ESLint based on provided options.
|
|
66
|
+
*
|
|
67
|
+
* @param options - The optional configuration object.
|
|
68
|
+
* @param options.convex - Whether to include Convex rules.
|
|
69
|
+
* @param options.functionStyle - The function style to enforce. Defaults to "arrow".
|
|
70
|
+
* @param options.ignores - Additional paths to ignore. Already excludes `node_modules` and `dist`.
|
|
71
|
+
* @param options.importPlugin - Whether to include the import plugin. Defaults to true.
|
|
72
|
+
* @param options.jsdoc - Whether to include JSDoc rules. Set to false to disable, or provide an object to configure.
|
|
73
|
+
* @param options.query - Whether to include TanStack Query rules.
|
|
74
|
+
* @param options.react - Whether to include React, React hooks, and React compiler rules.
|
|
75
|
+
* Can specify framework as "next", "none", "react-router", "remix", or "vite" to control related configs:
|
|
76
|
+
* - "next": Includes Next.js config, excludes React Refresh.
|
|
77
|
+
* - "vite" or "none": Includes React Refresh, excludes Next.js.
|
|
78
|
+
* - "remix" or "react-router": Excludes both Next.js and React Refresh (these frameworks handle their own refresh logic).
|
|
79
|
+
* - The reactRefresh property can override this framework-based behavior.
|
|
80
|
+
* @param options.sorting - Whether to include sorting rules from Perfectionist. Defaults to true.
|
|
81
|
+
* @param options.storybook - Whether to include Storybook rules. Defaults to false.
|
|
82
|
+
* @param options.testing - An object with the following properties:
|
|
83
|
+
* - `filenamePattern`: One of "spec" or "test" to determine which filename pattern to use.
|
|
84
|
+
* - `files`: Array of file patterns to include in the configuration.
|
|
85
|
+
* - `framework`: One of "vitest" or "jest" to determine which testing library to use.
|
|
86
|
+
* - `formattingRules`: Whether to include formatting rules like padding around blocks.
|
|
87
|
+
* - `itOrTest`: One of "it" or "test" to determine which test function to use.
|
|
88
|
+
* @param options.typescript - Whether to include TypeScript rules. Can be a boolean or a string with path to tsconfig.
|
|
89
|
+
* @param options.turbo - Whether to include Turborepo rules. Defaults to false.
|
|
90
|
+
* @param options.unicorn - Whether to include Unicorn rules. Defaults to true. Can be an object with filenameCase property.
|
|
91
|
+
* @param options.rules - This is for rules that you need to alter or turn off.
|
|
92
|
+
* @param additionalConfigs - Additional ESLint config objects to be merged into the final configuration.
|
|
93
|
+
* @returns An array of ESLint configuration objects.
|
|
94
|
+
*/
|
|
95
|
+
export const eslintConfig = (
|
|
96
|
+
{
|
|
97
|
+
convex = false,
|
|
98
|
+
functionStyle = "arrow",
|
|
99
|
+
ignores = [],
|
|
100
|
+
importPlugin = true,
|
|
101
|
+
jsdoc = { requireJsdoc: false },
|
|
102
|
+
query = false,
|
|
103
|
+
react = false,
|
|
104
|
+
rules,
|
|
105
|
+
sorting = true,
|
|
106
|
+
storybook = false,
|
|
107
|
+
testing = defaultTestingConfig,
|
|
108
|
+
turbo = false,
|
|
109
|
+
typescript = true,
|
|
110
|
+
unicorn = { filenameCase: "kebabCase" },
|
|
111
|
+
}: EslintConfigOptions = {},
|
|
112
|
+
...additionalConfigs: Linter.Config[]
|
|
113
|
+
): Linter.Config[] => {
|
|
114
|
+
// Categorize user's custom rules first
|
|
115
|
+
const categorizedRules = rules === undefined ? {} : processCustomRules(rules);
|
|
116
|
+
|
|
117
|
+
const usingNextjs = isObject(react) && react.framework === "next";
|
|
118
|
+
|
|
119
|
+
const configs: Linter.Config[] = [
|
|
120
|
+
ignoresConfig({
|
|
121
|
+
next: usingNextjs,
|
|
122
|
+
storybook,
|
|
123
|
+
userIgnores: ignores,
|
|
124
|
+
}),
|
|
125
|
+
baseEslintConfig(
|
|
126
|
+
functionStyle,
|
|
127
|
+
Boolean(typescript),
|
|
128
|
+
categorizedRules[configNames.base],
|
|
129
|
+
),
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
if (jsdoc !== false) {
|
|
133
|
+
configs.push(
|
|
134
|
+
jsdocConfig(
|
|
135
|
+
jsdoc.requireJsdoc ?? false,
|
|
136
|
+
categorizedRules[configNames.jsdoc],
|
|
137
|
+
),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (typescript) {
|
|
142
|
+
configs.push(
|
|
143
|
+
...(tseslintConfig(
|
|
144
|
+
isString(typescript) ? typescript : undefined,
|
|
145
|
+
categorizedRules[configNames.typescript],
|
|
146
|
+
) as Linter.Config[]),
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (importPlugin) {
|
|
151
|
+
configs.push(
|
|
152
|
+
importConfig(Boolean(typescript), categorizedRules[configNames.import]),
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (react) {
|
|
157
|
+
const reactOptions = isObject(react) ? react : {};
|
|
158
|
+
|
|
159
|
+
// Apply reactRefresh based on framework setting or explicit override
|
|
160
|
+
const shouldUseReactRefresh =
|
|
161
|
+
// Explicit setting takes precedence
|
|
162
|
+
reactOptions.reactRefresh === true ||
|
|
163
|
+
// Framework-based default (vite/none use reactRefresh by default)
|
|
164
|
+
((reactOptions.framework === "vite" ||
|
|
165
|
+
reactOptions.framework === "none") &&
|
|
166
|
+
reactOptions.reactRefresh !== false);
|
|
167
|
+
|
|
168
|
+
if (shouldUseReactRefresh) {
|
|
169
|
+
configs.push(
|
|
170
|
+
reactRefreshEslintConfig(categorizedRules[configNames.reactRefresh]),
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
configs.push(
|
|
175
|
+
reactEslintConfig({
|
|
176
|
+
customRules: categorizedRules[configNames.react],
|
|
177
|
+
functionStyle,
|
|
178
|
+
reactCompiler: reactOptions.reactCompiler ?? true,
|
|
179
|
+
typescript: Boolean(typescript),
|
|
180
|
+
}),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
if (usingNextjs) {
|
|
184
|
+
configs.push(nextjsConfig(categorizedRules[configNames.nextjs]));
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (query) {
|
|
189
|
+
configs.push(queryConfig(categorizedRules[configNames.query]));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (convex) {
|
|
193
|
+
configs.push(convexConfig(categorizedRules[configNames.convex]));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (testing !== false) {
|
|
197
|
+
// Use the provided testing config or the default if testing is true
|
|
198
|
+
const mergedTestingConfig: TestingConfig =
|
|
199
|
+
isObject(testing) ?
|
|
200
|
+
{ ...defaultTestingConfig, ...testing }
|
|
201
|
+
: defaultTestingConfig;
|
|
202
|
+
|
|
203
|
+
// Destructure from the merged config
|
|
204
|
+
const { filenamePattern, files, formattingRules, framework, itOrTest } =
|
|
205
|
+
mergedTestingConfig;
|
|
206
|
+
|
|
207
|
+
configs.push(
|
|
208
|
+
testingConfig(
|
|
209
|
+
{
|
|
210
|
+
filenamePattern,
|
|
211
|
+
files,
|
|
212
|
+
formattingRules,
|
|
213
|
+
framework,
|
|
214
|
+
itOrTest,
|
|
215
|
+
},
|
|
216
|
+
categorizedRules[configNames.testing],
|
|
217
|
+
),
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (sorting) {
|
|
222
|
+
configs.push(
|
|
223
|
+
perfectionistConfig(categorizedRules[configNames.perfectionist]),
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (unicorn) {
|
|
228
|
+
const filenameCase = isObject(unicorn) ? unicorn.filenameCase : undefined;
|
|
229
|
+
configs.push(
|
|
230
|
+
unicornConfig({
|
|
231
|
+
customRules: categorizedRules[configNames.unicorn],
|
|
232
|
+
filenameCase,
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (functionStyle === "arrow") {
|
|
238
|
+
configs.push(
|
|
239
|
+
preferArrowFunctionConfig(
|
|
240
|
+
categorizedRules[configNames.preferArrowFunction],
|
|
241
|
+
),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (storybook) {
|
|
246
|
+
configs.push(...storybookConfig(categorizedRules[configNames.storybook]));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (turbo) {
|
|
250
|
+
configs.push(turboConfig(categorizedRules[configNames.turbo]));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Add any additional config objects provided by the user
|
|
254
|
+
if (additionalConfigs.length > 0) {
|
|
255
|
+
configs.push(...additionalConfigs);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return configs;
|
|
259
|
+
};
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# JSDoc Configuration
|
|
2
|
+
|
|
3
|
+
JSDoc comment validation and formatting for better code documentation.
|
|
4
|
+
|
|
5
|
+
[← Back to main README](../../../README.md)
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
JSDoc configuration is **disabled by default** and provides:
|
|
10
|
+
|
|
11
|
+
- JSDoc comment validation
|
|
12
|
+
- Type and tag checking
|
|
13
|
+
- Parameter and return value documentation
|
|
14
|
+
- Formatting and style consistency
|
|
15
|
+
- TypeScript-aware (disables redundant type rules)
|
|
16
|
+
|
|
17
|
+
This plugin can be handy for libraries, but it can get annoying, so it's not for everyone. [See my configuration](./rules.ts), and feel free to customize via the `rules` option.
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
import { eslintConfig } from "js-style-kit";
|
|
23
|
+
|
|
24
|
+
export default eslintConfig({
|
|
25
|
+
jsdoc: true, // Enable JSDoc validation
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration Options
|
|
30
|
+
|
|
31
|
+
### Basic Enable
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
jsdoc: true, // Validation without requiring JSDoc on all functions
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Require JSDoc
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
jsdoc: {
|
|
41
|
+
requireJsdoc: true, // Enforce JSDoc on functions and classes
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## File Scope
|
|
46
|
+
|
|
47
|
+
JSDoc rules apply to:
|
|
48
|
+
|
|
49
|
+
- ✅ All `.js`, `.jsx`, `.ts`, `.tsx`, `.cjs`, `.mjs` files
|
|
50
|
+
- ❌ Excluded from `.test` and `.spec` files
|
|
51
|
+
|
|
52
|
+
## Validation Without Enforcement
|
|
53
|
+
|
|
54
|
+
By default (`requireJsdoc: false`), JSDoc comments are **validated but not required**:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
// ✅ Good - no JSDoc required, but valid if present
|
|
58
|
+
export const add = (a: number, b: number) => a + b;
|
|
59
|
+
|
|
60
|
+
// ✅ Good - JSDoc is validated when present
|
|
61
|
+
/**
|
|
62
|
+
* Adds two numbers together.
|
|
63
|
+
*
|
|
64
|
+
* @param a - First number
|
|
65
|
+
* @param b - Second number
|
|
66
|
+
* @returns Sum of the two numbers
|
|
67
|
+
*/
|
|
68
|
+
export const add = (a: number, b: number) => a + b;
|
|
69
|
+
|
|
70
|
+
// ❌ Bad - invalid JSDoc syntax
|
|
71
|
+
/**
|
|
72
|
+
* @param c - Wrong parameter name
|
|
73
|
+
*/
|
|
74
|
+
export const add = (a: number, b: number) => a + b;
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Active rules:**
|
|
78
|
+
|
|
79
|
+
- ✅ Validates JSDoc syntax and formatting
|
|
80
|
+
- ✅ Checks parameter names match function signature
|
|
81
|
+
- ✅ Verifies tag names are valid
|
|
82
|
+
- ❌ Does NOT require JSDoc on all functions
|
|
83
|
+
|
|
84
|
+
## Require JSDoc Mode
|
|
85
|
+
|
|
86
|
+
When `requireJsdoc: true`, documentation becomes mandatory:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
// ❌ Bad - missing JSDoc
|
|
90
|
+
export const add = (a: number, b: number) => a + b;
|
|
91
|
+
|
|
92
|
+
// ✅ Good - complete JSDoc
|
|
93
|
+
/**
|
|
94
|
+
* Adds two numbers together.
|
|
95
|
+
*
|
|
96
|
+
* @param a - First number
|
|
97
|
+
* @param b - Second number
|
|
98
|
+
* @returns Sum of the two numbers
|
|
99
|
+
*/
|
|
100
|
+
export const add = (a: number, b: number) => a + b;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Requires JSDoc on:**
|
|
104
|
+
|
|
105
|
+
- Function declarations
|
|
106
|
+
- Function expressions
|
|
107
|
+
- Arrow functions
|
|
108
|
+
- Class declarations
|
|
109
|
+
- Class expressions
|
|
110
|
+
- Method definitions
|
|
111
|
+
|
|
112
|
+
## TypeScript Integration
|
|
113
|
+
|
|
114
|
+
When using TypeScript, JSDoc rules automatically adjust:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// ✅ Good - TypeScript handles types
|
|
118
|
+
/**
|
|
119
|
+
* Calculates the total price with tax.
|
|
120
|
+
*
|
|
121
|
+
* @param price - Base price
|
|
122
|
+
* @param taxRate - Tax rate as decimal
|
|
123
|
+
* @returns Total price including tax
|
|
124
|
+
*/
|
|
125
|
+
export const calculateTotal = (price: number, taxRate: number): number => {
|
|
126
|
+
return price * (1 + taxRate);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// ❌ Bad - redundant type in JSDoc (TypeScript projects)
|
|
130
|
+
/**
|
|
131
|
+
* @param {number} price - Base price
|
|
132
|
+
* @param {number} taxRate - Tax rate
|
|
133
|
+
* @returns {number} Total
|
|
134
|
+
*/
|
|
135
|
+
export const calculateTotal = (price: number, taxRate: number): number => {
|
|
136
|
+
return price * (1 + taxRate);
|
|
137
|
+
};
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**TypeScript-specific behavior:**
|
|
141
|
+
|
|
142
|
+
- `jsdoc/no-types` is enabled (prevents redundant `{type}` annotations)
|
|
143
|
+
- `jsdoc/no-undefined-types` is disabled (TypeScript validates types)
|
|
144
|
+
- Type information comes from TypeScript, not JSDoc
|
|
145
|
+
|
|
146
|
+
## Key Rules
|
|
147
|
+
|
|
148
|
+
### Syntax Validation
|
|
149
|
+
|
|
150
|
+
- **`jsdoc/check-alignment`** - Enforces proper JSDoc alignment
|
|
151
|
+
- **`jsdoc/check-tag-names`** - Validates tag names are recognized
|
|
152
|
+
- **`jsdoc/check-types`** - Validates JSDoc types (non-TypeScript)
|
|
153
|
+
- **`jsdoc/valid-types`** - Ensures type syntax is valid
|
|
154
|
+
- **`jsdoc/empty-tags`** - Validates tags that shouldn't have content
|
|
155
|
+
|
|
156
|
+
### Parameter Documentation
|
|
157
|
+
|
|
158
|
+
- **`jsdoc/check-param-names`** - Parameter names match function signature
|
|
159
|
+
- **`jsdoc/require-param`** - Requires `@param` tags (when `requireJsdoc: true`)
|
|
160
|
+
- **`jsdoc/require-param-name`** - Ensures `@param` has parameter name
|
|
161
|
+
- **`jsdoc/require-param-description`** - Requires parameter descriptions
|
|
162
|
+
|
|
163
|
+
### Return Documentation
|
|
164
|
+
|
|
165
|
+
- **`jsdoc/require-returns`** - Requires `@returns` tag (when `requireJsdoc: true`)
|
|
166
|
+
- **`jsdoc/require-returns-check`** - Validates `@returns` matches return statement
|
|
167
|
+
- **`jsdoc/require-returns-description`** - Requires return value description
|
|
168
|
+
|
|
169
|
+
### Formatting
|
|
170
|
+
|
|
171
|
+
- **`jsdoc/multiline-blocks`** - Enforces multiline JSDoc format
|
|
172
|
+
- **`jsdoc/no-multi-asterisks`** - Prevents extra asterisks
|
|
173
|
+
- **`jsdoc/require-asterisk-prefix`** - Requires asterisk on each line
|
|
174
|
+
- **`jsdoc/tag-lines`** - Controls spacing between tags
|
|
175
|
+
|
|
176
|
+
### Other Rules
|
|
177
|
+
|
|
178
|
+
- **`jsdoc/check-access`** - Validates `@private`, `@public`, etc.
|
|
179
|
+
- **`jsdoc/check-property-names`** - Validates `@property` tag names
|
|
180
|
+
- **`jsdoc/implements-on-classes`** - Ensures `@implements` on classes only
|
|
181
|
+
- **`jsdoc/no-defaults`** - Prevents documenting default values
|
|
182
|
+
|
|
183
|
+
## Examples
|
|
184
|
+
|
|
185
|
+
### Function Documentation
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
/**
|
|
189
|
+
* Fetches user data from the API.
|
|
190
|
+
*
|
|
191
|
+
* @param userId - The unique identifier for the user
|
|
192
|
+
* @returns Promise resolving to user data
|
|
193
|
+
* @throws {Error} When the user is not found
|
|
194
|
+
*/
|
|
195
|
+
export const fetchUser = async (userId: string): Promise<User> => {
|
|
196
|
+
const response = await fetch(`/api/users/${userId}`);
|
|
197
|
+
if (!response.ok) throw new Error("User not found");
|
|
198
|
+
return response.json();
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Class Documentation
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
/**
|
|
206
|
+
* Manages user authentication and sessions.
|
|
207
|
+
*/
|
|
208
|
+
export class AuthService {
|
|
209
|
+
/**
|
|
210
|
+
* Authenticates a user with credentials.
|
|
211
|
+
*
|
|
212
|
+
* @param username - User's username
|
|
213
|
+
* @param password - User's password
|
|
214
|
+
* @returns Authentication token
|
|
215
|
+
*/
|
|
216
|
+
login(username: string, password: string): string {
|
|
217
|
+
// Implementation
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Logs out the current user.
|
|
222
|
+
*/
|
|
223
|
+
logout(): void {
|
|
224
|
+
// Implementation
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Interface Documentation
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
/**
|
|
233
|
+
* Represents a user in the system.
|
|
234
|
+
*/
|
|
235
|
+
interface User {
|
|
236
|
+
/** Unique user identifier */
|
|
237
|
+
id: string;
|
|
238
|
+
|
|
239
|
+
/** User's display name */
|
|
240
|
+
name: string;
|
|
241
|
+
|
|
242
|
+
/** User's email address */
|
|
243
|
+
email: string;
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Destructured Parameters
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
/**
|
|
251
|
+
* Creates a new user account.
|
|
252
|
+
*
|
|
253
|
+
* @param options - User creation options
|
|
254
|
+
* @param options.name - User's name
|
|
255
|
+
* @param options.email - User's email
|
|
256
|
+
* @param options.role - User's role in the system
|
|
257
|
+
* @returns Created user object
|
|
258
|
+
*/
|
|
259
|
+
export const createUser = ({
|
|
260
|
+
name,
|
|
261
|
+
email,
|
|
262
|
+
role,
|
|
263
|
+
}: {
|
|
264
|
+
name: string;
|
|
265
|
+
email: string;
|
|
266
|
+
role: string;
|
|
267
|
+
}): User => {
|
|
268
|
+
// Implementation
|
|
269
|
+
};
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Async Functions
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
/**
|
|
276
|
+
* Processes payment for an order.
|
|
277
|
+
*
|
|
278
|
+
* @param orderId - Order identifier
|
|
279
|
+
* @param amount - Payment amount
|
|
280
|
+
* @returns Promise resolving to payment confirmation
|
|
281
|
+
* @throws {PaymentError} When payment processing fails
|
|
282
|
+
*/
|
|
283
|
+
export const processPayment = async (
|
|
284
|
+
orderId: string,
|
|
285
|
+
amount: number,
|
|
286
|
+
): Promise<PaymentConfirmation> => {
|
|
287
|
+
// Implementation
|
|
288
|
+
};
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Tag Formatting
|
|
292
|
+
|
|
293
|
+
JSDoc enforces consistent tag spacing:
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
// ✅ Good - proper tag formatting
|
|
297
|
+
/**
|
|
298
|
+
* Description here.
|
|
299
|
+
*
|
|
300
|
+
* @param name - Parameter description
|
|
301
|
+
* @param age - Parameter description
|
|
302
|
+
* @returns Return description
|
|
303
|
+
*/
|
|
304
|
+
|
|
305
|
+
// ❌ Bad - extra lines between tags
|
|
306
|
+
/**
|
|
307
|
+
* Description here.
|
|
308
|
+
*
|
|
309
|
+
* @param name - Parameter description
|
|
310
|
+
*
|
|
311
|
+
* @param age - Parameter description
|
|
312
|
+
*
|
|
313
|
+
* @returns Return description
|
|
314
|
+
*/
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Rules:**
|
|
318
|
+
|
|
319
|
+
- One blank line between description and first tag
|
|
320
|
+
- No blank lines between `@param` tags
|
|
321
|
+
- Consistent formatting throughout
|
|
322
|
+
|
|
323
|
+
## Customization
|
|
324
|
+
|
|
325
|
+
### Require JSDoc on Exports Only
|
|
326
|
+
|
|
327
|
+
```js
|
|
328
|
+
export default eslintConfig({
|
|
329
|
+
jsdoc: { requireJsdoc: true },
|
|
330
|
+
rules: {
|
|
331
|
+
"jsdoc/require-jsdoc": [
|
|
332
|
+
"warn",
|
|
333
|
+
{
|
|
334
|
+
require: {
|
|
335
|
+
FunctionDeclaration: true,
|
|
336
|
+
// Only require JSDoc on exported functions
|
|
337
|
+
publicOnly: true,
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Allow JSDoc Types in TypeScript
|
|
346
|
+
|
|
347
|
+
```js
|
|
348
|
+
export default eslintConfig({
|
|
349
|
+
jsdoc: true,
|
|
350
|
+
rules: {
|
|
351
|
+
// Allow {type} annotations even in TypeScript
|
|
352
|
+
"jsdoc/no-types": "off",
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Disable Description Requirements
|
|
358
|
+
|
|
359
|
+
```js
|
|
360
|
+
export default eslintConfig({
|
|
361
|
+
jsdoc: true,
|
|
362
|
+
rules: {
|
|
363
|
+
"jsdoc/require-param-description": "off",
|
|
364
|
+
"jsdoc/require-returns-description": "off",
|
|
365
|
+
},
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Common Patterns
|
|
370
|
+
|
|
371
|
+
### Library Development
|
|
372
|
+
|
|
373
|
+
```js
|
|
374
|
+
export default eslintConfig({
|
|
375
|
+
typescript: true,
|
|
376
|
+
jsdoc: { requireJsdoc: true }, // Require docs for public API
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Application Development
|
|
381
|
+
|
|
382
|
+
```js
|
|
383
|
+
export default eslintConfig({
|
|
384
|
+
typescript: true,
|
|
385
|
+
jsdoc: true, // Validate JSDoc but don't require it
|
|
386
|
+
});
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Related Configurations
|
|
390
|
+
|
|
391
|
+
- [TypeScript](../typescript/README.md) - TypeScript type checking
|
|
392
|
+
- [Base](../base/README.md) - Base ESLint rules
|
|
393
|
+
|
|
394
|
+
## Learn More
|
|
395
|
+
|
|
396
|
+
- [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc)
|
|
397
|
+
- [JSDoc Official](https://jsdoc.app/)
|
|
398
|
+
- [TypeScript JSDoc Reference](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
|
|
399
|
+
- [Main README](../../../README.md)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import jsdoc from "eslint-plugin-jsdoc";
|
|
2
|
+
|
|
3
|
+
import type { EslintConfigObject, EslintRuleConfig } from "../types.js";
|
|
4
|
+
|
|
5
|
+
import { configNames } from "../constants.js";
|
|
6
|
+
import { jsdocRules } from "./rules.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generates ESLint configuration for JSDoc comments.
|
|
10
|
+
*
|
|
11
|
+
* @param requireJsdoc - Whether to enforce JSDoc comments on functions and classes. Defaults to false.
|
|
12
|
+
* @param customRules - Optional object containing custom rules to override or add to the JSDoc configuration.
|
|
13
|
+
* @returns An ESLint configuration object for JSDoc comments.
|
|
14
|
+
*/
|
|
15
|
+
export const jsdocConfig = (
|
|
16
|
+
requireJsdoc = false,
|
|
17
|
+
customRules?: Record<string, EslintRuleConfig>,
|
|
18
|
+
): EslintConfigObject => ({
|
|
19
|
+
files: ["**/*.{js,jsx,ts,tsx,cjs,mjs}"],
|
|
20
|
+
ignores: ["**/*.{test,spec}.{js,jsx,ts,tsx,cjs,mjs}"],
|
|
21
|
+
name: configNames.jsdoc,
|
|
22
|
+
plugins: {
|
|
23
|
+
jsdoc,
|
|
24
|
+
},
|
|
25
|
+
rules: {
|
|
26
|
+
...jsdocRules(requireJsdoc),
|
|
27
|
+
...(customRules ?? {}),
|
|
28
|
+
},
|
|
29
|
+
});
|