@dmitryrechkin/eslint-standard 1.1.2 โ†’ 1.1.4

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 CHANGED
@@ -9,6 +9,7 @@ A comprehensive ESLint configuration package with TypeScript support, featuring
9
9
  - ๐Ÿ”„ **Automatic Import Sorting**: Organizes imports with type imports and regular imports properly grouped
10
10
  - ๐Ÿ—๏ธ **Class Member Ordering**: Auto-reorders class members by visibility (public โ†’ protected โ†’ private) and type (fields โ†’ constructor โ†’ methods)
11
11
  - ๐Ÿ“ **JSDoc Alignment**: Automatically fixes JSDoc comment indentation and alignment with proper tab formatting
12
+ - ๐Ÿ“‘ **JSDoc Requirements**: Enforces comprehensive JSDoc documentation with auto-generation of comment blocks
12
13
  - ๐Ÿงน **Unused Import Removal**: Automatically detects and removes unused imports
13
14
 
14
15
  ### **Code Style Enforcement**
@@ -16,6 +17,7 @@ A comprehensive ESLint configuration package with TypeScript support, featuring
16
17
  - **Modern JavaScript**: Supports ECMAScript 2020 and newer features
17
18
  - **Consistent Formatting**: Enforces Allman brace style, tab indentation, single quotes, and semicolons
18
19
  - **Naming Conventions**: Comprehensive naming rules for variables, functions, classes, and more
20
+ - **JSDoc Documentation**: Requires comprehensive documentation for all exported functions, classes, methods, interfaces, types, and enums
19
21
  - **Customizable**: Flexible configuration options for different project needs
20
22
 
21
23
  ## ๐Ÿ“ฆ Installation
@@ -68,7 +70,14 @@ export default eslintStandard({
68
70
  rules: {
69
71
  // Override or add custom rules
70
72
  'no-console': 'warn',
71
- 'perfectionist/sort-classes': 'off' // Disable auto class member sorting if needed
73
+ 'perfectionist/sort-classes': 'off', // Disable auto class member sorting if needed
74
+ // Disable JSDoc requirements if needed
75
+ 'jsdoc/require-jsdoc': 'off',
76
+ 'jsdoc/require-description': 'off',
77
+ // Disable type hint requirements (if you prefer TypeScript-only types)
78
+ 'jsdoc/require-param-type': 'off',
79
+ 'jsdoc/require-returns-type': 'off',
80
+ 'jsdoc/no-types': ['error', { contexts: ['any'] }]
72
81
  }
73
82
  });
74
83
  ```
@@ -131,7 +140,10 @@ When you run `eslint --fix`, this configuration will automatically:
131
140
  2. **๐Ÿ”„ Reorder Class Members**: Arrange class members by visibility and type:
132
141
  - Static properties โ†’ Instance properties โ†’ Constructor โ†’ Static methods โ†’ Instance methods
133
142
  - Within each group: public โ†’ protected โ†’ private
134
- 3. **๐Ÿ“ Fix JSDoc Indentation**: Align JSDoc comments with proper tab indentation
143
+ 3. **๐Ÿ“ Fix JSDoc Comments**:
144
+ - Generate missing JSDoc comment blocks for functions, classes, methods, interfaces, types, and enums
145
+ - Align JSDoc comments with proper tab indentation
146
+ - Add parameter and return value placeholders
135
147
  4. **๐Ÿงน Remove Unused Imports**: Clean up unused import statements
136
148
  5. **โœจ Format Code**: Apply consistent spacing, quotes, semicolons, and brace styles
137
149
 
@@ -195,6 +207,44 @@ export class UserService
195
207
  }
196
208
  ```
197
209
 
210
+ #### JSDoc Documentation with Type Hints
211
+ ```typescript
212
+ // โŒ Before - Missing JSDoc
213
+ export function processUser(userData: UserData): ProcessedResult {
214
+ return process(userData);
215
+ }
216
+
217
+ // โš ๏ธ After (auto-fixed) - JSDoc block generated but missing type hints
218
+ /**
219
+ *
220
+ * @param userData
221
+ * @returns
222
+ */
223
+ export function processUser(userData: UserData): ProcessedResult {
224
+ return process(userData);
225
+ }
226
+
227
+ // โŒ Still fails - Missing type hints and descriptions
228
+ // ESLint errors:
229
+ // - Missing JSDoc @param "userData" type
230
+ // - Missing JSDoc @param "userData" description
231
+ // - Missing JSDoc @returns type
232
+ // - Missing JSDoc block description
233
+
234
+ // โœ… Complete JSDoc with type hints (must be added manually)
235
+ /**
236
+ * Processes user data and returns formatted result.
237
+ * @param {UserData} userData - The user data to process
238
+ * @returns {ProcessedResult} The processed user result
239
+ */
240
+ export function processUser(userData: UserData): ProcessedResult {
241
+ return process(userData);
242
+ }
243
+
244
+ // โš ๏ธ Note: ESLint cannot auto-generate type hints from TypeScript types.
245
+ // Type annotations must be added manually to satisfy the linter requirements.
246
+ ```
247
+
198
248
  #### JSDoc Alignment
199
249
  ```typescript
200
250
  // โŒ Before
@@ -220,6 +270,56 @@ export class UserService
220
270
  - **Enum Members**: `UPPER_CASE` or `PascalCase`
221
271
  - **Type Parameters**: `PascalCase`
222
272
 
273
+ ### ๐Ÿ“ JSDoc with Type Hints Requirements
274
+
275
+ This configuration requires comprehensive JSDoc documentation with type hints:
276
+
277
+ - **Type Annotations Required**: All parameters and return values must include JSDoc type hints
278
+ - **Description Required**: All functions, parameters, and return values must have descriptions
279
+ - **Auto-generation Limited**: ESLint can generate JSDoc blocks but cannot infer TypeScript types
280
+ - **Manual Completion Needed**: Type hints must be added manually after auto-generation
281
+
282
+ #### Required JSDoc Format
283
+
284
+ ```javascript
285
+ /**
286
+ * Function description is required.
287
+ * @param {string} name - Parameter description is required
288
+ * @param {number} age - Type hint {number} is required
289
+ * @returns {string} Return type and description required
290
+ */
291
+ function greet(name: string, age: number): string {
292
+ return `Hello ${name}, you are ${age} years old`;
293
+ }
294
+ ```
295
+
296
+ #### Common Type Hint Patterns
297
+
298
+ ```javascript
299
+ // Basic types
300
+ @param {string} name
301
+ @param {number} count
302
+ @param {boolean} isActive
303
+ @param {Object} config
304
+ @param {Array<string>} items
305
+ @param {Function} callback
306
+
307
+ // Complex types
308
+ @param {UserData} userData - Custom type
309
+ @param {Promise<Response>} response - Generic type
310
+ @param {string|number} id - Union type
311
+ @param {{name: string, age: number}} person - Object type
312
+ @param {string[]} names - Array shorthand
313
+ @returns {void} - For functions with no return
314
+ ```
315
+
316
+ #### Important Notes
317
+
318
+ 1. **ESLint Cannot Auto-Generate Types**: While ESLint can create JSDoc blocks, it cannot determine TypeScript types
319
+ 2. **Manual Work Required**: After running `--fix`, you must manually add all type hints
320
+ 3. **Duplication with TypeScript**: This approach duplicates type information already in TypeScript
321
+ 4. **Maintenance Overhead**: Types must be kept in sync between TypeScript and JSDoc
322
+
223
323
  ## โš ๏ธ Troubleshooting
224
324
 
225
325
  ### Peer Dependency Warnings
package/eslint.config.mjs CHANGED
@@ -155,6 +155,49 @@ export default function ({
155
155
  'jsdoc/check-indentation': 'off', // Disabled to avoid conflicts with our custom plugin
156
156
  'jsdoc/tag-lines': 'off', // Disabled to avoid conflicts with our custom plugin
157
157
  'jsdoc-indent/jsdoc-indent': ['error', { tabWidth: 4 }],
158
+
159
+ // JSDoc requirements with type hints
160
+ 'jsdoc/require-jsdoc': ['error', {
161
+ enableFixer: false, // Don't auto-generate empty JSDoc blocks
162
+ require: {
163
+ FunctionDeclaration: true,
164
+ MethodDefinition: true,
165
+ ClassDeclaration: true,
166
+ ArrowFunctionExpression: true,
167
+ FunctionExpression: true
168
+ },
169
+ contexts: [
170
+ 'TSInterfaceDeclaration',
171
+ 'TSTypeAliasDeclaration',
172
+ 'TSEnumDeclaration'
173
+ // Removed 'ClassProperty' and 'PropertyDefinition' - no JSDoc required for properties
174
+ ]
175
+ }],
176
+ 'jsdoc/require-description': 'error',
177
+ 'jsdoc/require-param': 'error',
178
+ 'jsdoc/require-param-description': 'error',
179
+ 'jsdoc/require-param-name': 'error',
180
+ 'jsdoc/require-returns': 'error',
181
+ 'jsdoc/require-returns-description': 'error',
182
+ 'jsdoc/check-param-names': 'error',
183
+ 'jsdoc/check-tag-names': 'error',
184
+ 'jsdoc/check-types': 'error',
185
+ 'jsdoc/valid-types': 'error',
186
+ 'jsdoc/no-undefined-types': 'error',
187
+ 'jsdoc/require-yields': 'error',
188
+ 'jsdoc/require-throws': 'error',
189
+ 'jsdoc/check-alignment': 'off', // Handled by custom plugin
190
+ 'jsdoc/multiline-blocks': ['error', {
191
+ noMultilineBlocks: false,
192
+ minimumLengthForMultiline: 40
193
+ }],
194
+
195
+ // JSDoc with type hints requirements
196
+ 'jsdoc/require-param-type': 'error', // Require type hints for parameters
197
+ 'jsdoc/require-returns-type': 'error', // Require type hints for returns
198
+ 'jsdoc/no-types': 'off', // Allow type annotations in JSDoc
199
+ 'jsdoc/check-types': 'error', // Ensure valid JSDoc types
200
+ 'jsdoc/valid-types': 'error', // Validate type syntax
158
201
 
159
202
  // Enhanced: Interface brace style
160
203
  'interface-brace/interface-brace-style': 'error',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dmitryrechkin/eslint-standard",
3
3
  "description": "This package provides a shared ESLint configuration which includes TypeScript support and a set of specific linting rules designed to ensure high-quality and consistent code style across projects.",
4
- "version": "1.1.2",
4
+ "version": "1.1.4",
5
5
  "main": "eslint.config.mjs",
6
6
  "bin": {
7
7
  "eslint-standard": "./src/cli/index.mjs"
@@ -15,8 +15,10 @@
15
15
  "scripts": {
16
16
  "postinstall": "node src/cli/postinstall.mjs",
17
17
  "package:publish": "npm publish --access public",
18
- "test": "npm run test:formatting",
19
- "test:formatting": "node tests/test-runner.js"
18
+ "test": "npm run test:formatting && npm run test:cli",
19
+ "test:formatting": "node tests/test-runner.js",
20
+ "test:cli": "node tests/test-cli.js",
21
+ "test:install": "node tests/test-install-simulation.js"
20
22
  },
21
23
  "keywords": [],
22
24
  "author": "",
@@ -3,20 +3,32 @@
3
3
  import { readFileSync } from 'fs';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { dirname, join, resolve } from 'path';
6
+ import { spawn } from 'child_process';
6
7
 
7
8
  const __filename = fileURLToPath(import.meta.url);
8
9
  const __dirname = dirname(__filename);
9
10
 
11
+ // Check for --install flag
12
+ const shouldInstall = process.argv.includes('--install');
13
+
10
14
  // Get peer dependencies
11
15
  const packageJsonPath = join(__dirname, '../../package.json');
12
16
  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
13
17
  const peerDeps = packageJson.peerDependencies || {};
14
18
 
15
- // Check if running from node_modules
19
+ // Check if running from node_modules and find project root
16
20
  const isInNodeModules = __dirname.includes('node_modules');
17
- const projectRoot = isInNodeModules
18
- ? resolve(__dirname, '../../../../')
19
- : process.cwd();
21
+ let projectRoot;
22
+
23
+ if (isInNodeModules) {
24
+ // Handle different package manager structures
25
+ // pnpm: .pnpm/@org+pkg@version_deps/node_modules/@org/pkg
26
+ // npm/yarn: node_modules/@org/pkg
27
+ const parts = __dirname.split('node_modules');
28
+ projectRoot = parts[0].replace(/[\\/]$/, ''); // Remove trailing slash
29
+ } else {
30
+ projectRoot = process.cwd();
31
+ }
20
32
 
21
33
  // Read project's package.json
22
34
  let projectPackageJson;
@@ -56,13 +68,33 @@ if (missingDeps.length === 0 && outdatedDeps.length === 0) {
56
68
  } else {
57
69
  if (missingDeps.length > 0) {
58
70
  console.log(`\nโŒ Missing ${missingDeps.length} dependencies:`);
59
- console.log('Run: npx @dmitryrechkin/eslint-standard install-deps');
71
+ missingDeps.forEach(dep => console.log(` - ${dep}`));
72
+
73
+ if (shouldInstall) {
74
+ console.log('\n๐Ÿ”ง Auto-installing missing dependencies...\n');
75
+
76
+ // Import and run the install-deps script
77
+ try {
78
+ const installDepsModule = await import('./install-deps.mjs');
79
+ // The install-deps script will handle the installation
80
+ } catch (error) {
81
+ console.error('โŒ Failed to auto-install dependencies:', error.message);
82
+ process.exit(1);
83
+ }
84
+ } else {
85
+ console.log('\n๐Ÿ’ก To install missing dependencies:');
86
+ console.log(' npx @dmitryrechkin/eslint-standard install-deps');
87
+ console.log(' or run this command with --install flag');
88
+ }
60
89
  }
61
90
  if (outdatedDeps.length > 0) {
62
91
  console.log(`\nโš ๏ธ ${outdatedDeps.length} dependencies may be outdated:`);
63
92
  outdatedDeps.forEach(dep => console.log(` - ${dep}`));
64
93
  }
65
- process.exit(1);
94
+
95
+ if (!shouldInstall && missingDeps.length > 0) {
96
+ process.exit(1);
97
+ }
66
98
  }
67
99
 
68
100
  export default function checkDeps() {
package/src/cli/index.mjs CHANGED
@@ -20,13 +20,15 @@ Usage:
20
20
  npx @dmitryrechkin/eslint-standard <command>
21
21
 
22
22
  Commands:
23
- install-deps Install all peer dependencies
24
- check-deps Check if all peer dependencies are installed
25
- help Show this help message
23
+ install-deps Install all peer dependencies
24
+ check-deps Check if all peer dependencies are installed
25
+ check-deps --install Auto-install missing dependencies if any
26
+ help Show this help message
26
27
 
27
28
  Examples:
28
29
  npx @dmitryrechkin/eslint-standard install-deps
29
30
  npx @dmitryrechkin/eslint-standard check-deps
31
+ npx @dmitryrechkin/eslint-standard check-deps --install
30
32
  `);
31
33
  break;
32
34
  default:
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync, existsSync } from 'fs';
4
+ import { fileURLToPath } from 'url';
5
+ import { dirname, join } from 'path';
6
+ import { execSync } from 'child_process';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+
11
+ // Don't run during local development
12
+ if (!__dirname.includes('node_modules')) {
13
+ process.exit(0);
14
+ }
15
+
16
+ // Check if we're in CI environment
17
+ const isCI = process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.GITHUB_ACTIONS;
18
+
19
+ // Check if scripts are disabled
20
+ const npmConfigIgnoreScripts = process.env.npm_config_ignore_scripts === 'true';
21
+
22
+ if (isCI || npmConfigIgnoreScripts) {
23
+ // Silent exit in CI or when scripts are disabled
24
+ process.exit(0);
25
+ }
26
+
27
+ // Simple check for missing dependencies
28
+ try {
29
+ const packageJsonPath = join(__dirname, '../../package.json');
30
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
31
+ const peerDeps = Object.keys(packageJson.peerDependencies || {});
32
+
33
+ // Quick check if any peer deps are missing
34
+ let missingCount = 0;
35
+ for (const dep of peerDeps) {
36
+ try {
37
+ // Try to resolve the dependency
38
+ require.resolve(dep, { paths: [process.cwd()] });
39
+ } catch {
40
+ missingCount++;
41
+ }
42
+ }
43
+
44
+ if (missingCount > 0) {
45
+ console.log(`
46
+ โš ๏ธ @dmitryrechkin/eslint-standard: ${missingCount} peer dependencies are missing!
47
+
48
+ Run this command to check and install them:
49
+ ๐Ÿ‘‰ ${'\x1b[36m'}npx @dmitryrechkin/eslint-standard check-deps --install${'\x1b[0m'}
50
+ `);
51
+ }
52
+ } catch (error) {
53
+ // Silent fail - don't break installation
54
+ }
@@ -11,6 +11,17 @@ if (!__dirname.includes('node_modules')) {
11
11
  process.exit(0);
12
12
  }
13
13
 
14
+ // Check environment variables for auto-install preference
15
+ const autoInstall = process.env.ESLINT_STANDARD_AUTO_INSTALL === 'true';
16
+ const skipInstall = process.env.ESLINT_STANDARD_SKIP_INSTALL === 'true';
17
+
18
+ // Check if we're in CI environment
19
+ const isCI = process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.GITHUB_ACTIONS;
20
+
21
+ if (skipInstall || isCI) {
22
+ process.exit(0);
23
+ }
24
+
14
25
  console.log(`
15
26
  โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
16
27
  โ•‘ โ•‘
@@ -21,9 +32,9 @@ console.log(`
21
32
  ๐Ÿ“ฆ This package requires peer dependencies to work properly.
22
33
 
23
34
  ๐Ÿš€ Quick install (auto-detects your package manager):
24
- ${'\x1b[36m'}npx @dmitryrechkin/eslint-standard install-deps${'\x1b[0m'}
35
+ ${'\x1b[36m'}npx @dmitryrechkin/eslint-standard check-deps --install${'\x1b[0m'}
25
36
 
26
- ๐Ÿ“‹ Or install manually:
37
+ ๐Ÿ“‹ Or install all dependencies directly:
27
38
  ${'\x1b[90m'}npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-unused-imports @stylistic/eslint-plugin eslint-plugin-jsdoc eslint-plugin-simple-import-sort eslint-plugin-perfectionist${'\x1b[0m'}
28
39
 
29
40
  ๐Ÿ” To check if all dependencies are installed:
@@ -32,9 +43,22 @@ console.log(`
32
43
  ๐Ÿ“š Documentation: https://github.com/dmitryrechkin/eslint-standard
33
44
  `);
34
45
 
35
- // Run check-deps to show current status
36
- try {
37
- await import('./check-deps.mjs');
38
- } catch (error) {
39
- // Silent fail - don't break installation
46
+ // Don't run check-deps in postinstall to avoid errors
47
+ // Users can run it manually with: npx @dmitryrechkin/eslint-standard check-deps
48
+
49
+ if (autoInstall) {
50
+ console.log('\n๐Ÿค– Auto-install enabled via ESLINT_STANDARD_AUTO_INSTALL=true');
51
+ console.log('๐Ÿ“ฆ Checking and installing peer dependencies...\n');
52
+
53
+ try {
54
+ // Run check-deps with --install flag
55
+ const { execSync } = await import('child_process');
56
+ execSync('node ' + join(__dirname, 'index.mjs') + ' check-deps --install', {
57
+ stdio: 'inherit',
58
+ cwd: process.cwd()
59
+ });
60
+ } catch (error) {
61
+ console.error('โŒ Auto-install failed. Please run manually:');
62
+ console.error(' npx @dmitryrechkin/eslint-standard check-deps --install');
63
+ }
40
64
  }
@@ -103,7 +103,7 @@ const interfaceBraceRule = {
103
103
  // Replace the space before the brace with a newline and proper indentation
104
104
  return fixer.replaceTextRange(
105
105
  [equalsToken.range[1], openingBrace.range[0]],
106
- ' =\n' + baseIndent
106
+ '\n' + baseIndent
107
107
  );
108
108
  }
109
109
  });