eslint-plugin-traceability 1.7.0 → 1.8.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/CHANGELOG.md +82 -0
- package/README.md +73 -32
- package/docs/ci-cd-pipeline.md +224 -0
- package/docs/cli-integration.md +22 -0
- package/docs/code-quality-refactor-opportunities-2025-12-03.md +78 -0
- package/docs/config-presets.md +38 -0
- package/docs/conventional-commits-guide.md +185 -0
- package/docs/custom-rules-development-guide.md +659 -0
- package/docs/decisions/0001-allow-dynamic-require-for-built-plugins.md +26 -0
- package/docs/decisions/001-typescript-for-eslint-plugin.accepted.md +111 -0
- package/docs/decisions/002-jest-for-eslint-testing.accepted.md +137 -0
- package/docs/decisions/003-code-quality-ratcheting-plan.md +48 -0
- package/docs/decisions/004-automated-version-bumping-for-ci-cd.md +196 -0
- package/docs/decisions/005-github-actions-validation-tooling.accepted.md +144 -0
- package/docs/decisions/006-semantic-release-for-automated-publishing.accepted.md +227 -0
- package/docs/decisions/007-github-releases-over-changelog.accepted.md +216 -0
- package/docs/decisions/008-ci-audit-flags.accepted.md +60 -0
- package/docs/decisions/009-security-focused-lint-rules.accepted.md +64 -0
- package/docs/decisions/010-implements-annotation-for-multi-story-requirements.proposed.md +184 -0
- package/docs/decisions/adr-0001-console-usage-for-cli-guards.md +190 -0
- package/docs/decisions/adr-accept-dev-dep-risk-glob.md +40 -0
- package/docs/decisions/adr-commit-branch-tests.md +54 -0
- package/docs/decisions/adr-maintenance-cli-interface.md +140 -0
- package/docs/decisions/adr-pre-push-parity.md +112 -0
- package/docs/decisions/code-quality-ratcheting-plan.md +53 -0
- package/docs/dependency-health.md +238 -0
- package/docs/eslint-9-setup-guide.md +517 -0
- package/docs/eslint-plugin-development-guide.md +487 -0
- package/docs/functionality-coverage-2025-12-03.md +250 -0
- package/docs/jest-testing-guide.md +100 -0
- package/docs/rules/prefer-implements-annotation.md +219 -0
- package/docs/rules/require-branch-annotation.md +71 -0
- package/docs/rules/require-req-annotation.md +203 -0
- package/docs/rules/require-story-annotation.md +159 -0
- package/docs/rules/valid-annotation-format.md +418 -0
- package/docs/rules/valid-req-reference.md +153 -0
- package/docs/rules/valid-story-reference.md +120 -0
- package/docs/security-incidents/2025-11-17-glob-cli-incident.md +45 -0
- package/docs/security-incidents/2025-11-18-brace-expansion-redos.md +45 -0
- package/docs/security-incidents/2025-11-18-bundled-dev-deps-accepted-risk.md +93 -0
- package/docs/security-incidents/2025-11-18-tar-race-condition.md +43 -0
- package/docs/security-incidents/2025-12-03-dependency-health-review.md +58 -0
- package/docs/security-incidents/SECURITY-INCIDENT-2025-11-18-semantic-release-bundled-npm.known-error.md +104 -0
- package/docs/security-incidents/SECURITY-INCIDENT-TEMPLATE.md +37 -0
- package/docs/security-incidents/dependency-override-rationale.md +57 -0
- package/docs/security-incidents/dev-deps-high.json +116 -0
- package/docs/security-incidents/handling-procedure.md +54 -0
- package/docs/stories/001.0-DEV-PLUGIN-SETUP.story.md +92 -0
- package/docs/stories/002.0-DEV-ESLINT-CONFIG.story.md +82 -0
- package/docs/stories/003.0-DEV-FUNCTION-ANNOTATIONS.story.md +112 -0
- package/docs/stories/004.0-DEV-BRANCH-ANNOTATIONS.story.md +153 -0
- package/docs/stories/005.0-DEV-ANNOTATION-VALIDATION.story.md +138 -0
- package/docs/stories/006.0-DEV-FILE-VALIDATION.story.md +144 -0
- package/docs/stories/007.0-DEV-ERROR-REPORTING.story.md +163 -0
- package/docs/stories/008.0-DEV-AUTO-FIX.story.md +150 -0
- package/docs/stories/009.0-DEV-MAINTENANCE-TOOLS.story.md +117 -0
- package/docs/stories/010.0-DEV-DEEP-VALIDATION.story.md +124 -0
- package/docs/stories/010.1-DEV-CONFIGURABLE-PATTERNS.story.md +149 -0
- package/docs/stories/010.2-DEV-MULTI-STORY-SUPPORT.story.md +216 -0
- package/docs/stories/010.3-DEV-MIGRATE-TO-IMPLEMENTS.story.md +236 -0
- package/docs/stories/developer-story.map.md +120 -0
- package/docs/ts-jest-presets-guide.md +548 -0
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.js +2 -0
- package/lib/src/maintenance/batch.d.ts +5 -0
- package/lib/src/maintenance/batch.js +5 -0
- package/lib/src/maintenance/cli.js +34 -212
- package/lib/src/maintenance/commands.d.ts +32 -0
- package/lib/src/maintenance/commands.js +139 -0
- package/lib/src/maintenance/detect.d.ts +2 -0
- package/lib/src/maintenance/detect.js +4 -0
- package/lib/src/maintenance/flags.d.ts +99 -0
- package/lib/src/maintenance/flags.js +121 -0
- package/lib/src/maintenance/report.d.ts +2 -0
- package/lib/src/maintenance/report.js +2 -0
- package/lib/src/maintenance/update.d.ts +4 -0
- package/lib/src/maintenance/update.js +4 -0
- package/lib/src/rules/helpers/require-story-io.d.ts +3 -0
- package/lib/src/rules/helpers/require-story-io.js +20 -6
- package/lib/src/rules/helpers/valid-annotation-format-internal.d.ts +30 -0
- package/lib/src/rules/helpers/valid-annotation-format-internal.js +36 -0
- package/lib/src/rules/helpers/valid-annotation-options.js +15 -4
- package/lib/src/rules/helpers/valid-annotation-utils.js +5 -0
- package/lib/src/rules/helpers/valid-implements-utils.d.ts +75 -0
- package/lib/src/rules/helpers/valid-implements-utils.js +149 -0
- package/lib/src/rules/helpers/valid-story-reference-helpers.d.ts +3 -4
- package/lib/src/rules/prefer-implements-annotation.d.ts +39 -0
- package/lib/src/rules/prefer-implements-annotation.js +276 -0
- package/lib/src/rules/valid-annotation-format.js +87 -28
- package/lib/src/rules/valid-req-reference.js +71 -0
- package/lib/src/utils/reqAnnotationDetection.d.ts +4 -1
- package/lib/src/utils/reqAnnotationDetection.js +43 -15
- package/lib/tests/maintenance/cli.test.js +89 -0
- package/lib/tests/plugin-default-export-and-configs.test.js +3 -0
- package/lib/tests/rules/prefer-implements-annotation.test.d.ts +1 -0
- package/lib/tests/rules/prefer-implements-annotation.test.js +84 -0
- package/lib/tests/rules/require-req-annotation.test.js +8 -1
- package/lib/tests/rules/require-story-annotation.test.js +9 -4
- package/lib/tests/rules/valid-annotation-format.test.js +78 -0
- package/lib/tests/rules/valid-req-reference.test.js +34 -0
- package/lib/tests/utils/ts-language-options.d.ts +1 -7
- package/lib/tests/utils/ts-language-options.js +8 -5
- package/package.json +7 -3
- package/user-docs/api-reference.md +507 -0
- package/user-docs/eslint-9-setup-guide.md +639 -0
- package/user-docs/examples.md +74 -0
- package/user-docs/migration-guide.md +158 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
# ESLint Plugin Development Guidance
|
|
2
|
+
|
|
3
|
+
This document provides comprehensive guidance for developing ESLint plugins, specifically tailored for the eslint-plugin-traceability project. It's based on the official [ESLint plugin documentation](https://eslint.org/docs/latest/extend/plugins) and includes project-specific considerations.
|
|
4
|
+
|
|
5
|
+
## Plugin Structure Overview
|
|
6
|
+
|
|
7
|
+
An ESLint plugin is a JavaScript object that exposes specific properties to ESLint:
|
|
8
|
+
|
|
9
|
+
- `meta` - information about the plugin
|
|
10
|
+
- `configs` - an object containing named configurations
|
|
11
|
+
- `rules` - an object containing custom rule definitions
|
|
12
|
+
- `processors` - an object containing named processors
|
|
13
|
+
|
|
14
|
+
## Basic Plugin Template
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// src/index.ts
|
|
18
|
+
const plugin = {
|
|
19
|
+
meta: {
|
|
20
|
+
name: "eslint-plugin-traceability",
|
|
21
|
+
version: "1.0.0",
|
|
22
|
+
namespace: "traceability",
|
|
23
|
+
},
|
|
24
|
+
configs: {},
|
|
25
|
+
rules: {},
|
|
26
|
+
processors: {},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// for ESM source (compiled to CommonJS)
|
|
30
|
+
export default plugin;
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Meta Data Requirements
|
|
34
|
+
|
|
35
|
+
### Essential Meta Properties
|
|
36
|
+
|
|
37
|
+
Every plugin should include meta information for debugging and caching:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
const plugin = {
|
|
41
|
+
meta: {
|
|
42
|
+
name: "eslint-plugin-traceability", // npm package name
|
|
43
|
+
version: "1.0.0", // npm package version
|
|
44
|
+
namespace: "traceability", // prefix for rules/configs
|
|
45
|
+
},
|
|
46
|
+
// ... other properties
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Reading from package.json
|
|
51
|
+
|
|
52
|
+
For maintainability, read name and version from package.json:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import fs from "fs";
|
|
56
|
+
import { fileURLToPath } from "url";
|
|
57
|
+
import { dirname, join } from "path";
|
|
58
|
+
|
|
59
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
60
|
+
const __dirname = dirname(__filename);
|
|
61
|
+
|
|
62
|
+
const pkg = JSON.parse(
|
|
63
|
+
fs.readFileSync(join(__dirname, "../package.json"), "utf8"),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const plugin = {
|
|
67
|
+
meta: {
|
|
68
|
+
name: pkg.name,
|
|
69
|
+
version: pkg.version,
|
|
70
|
+
namespace: "traceability",
|
|
71
|
+
},
|
|
72
|
+
// ... other properties
|
|
73
|
+
};
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Rule Development
|
|
77
|
+
|
|
78
|
+
### Rule Structure
|
|
79
|
+
|
|
80
|
+
Rules are the core functionality of an ESLint plugin:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const plugin = {
|
|
84
|
+
meta: {
|
|
85
|
+
name: "eslint-plugin-traceability",
|
|
86
|
+
version: "1.0.0",
|
|
87
|
+
namespace: "traceability",
|
|
88
|
+
},
|
|
89
|
+
rules: {
|
|
90
|
+
"require-story-annotation": {
|
|
91
|
+
meta: {
|
|
92
|
+
type: "problem",
|
|
93
|
+
docs: {
|
|
94
|
+
description: "require @story annotations on functions",
|
|
95
|
+
category: "Traceability",
|
|
96
|
+
recommended: true,
|
|
97
|
+
},
|
|
98
|
+
schema: [
|
|
99
|
+
{
|
|
100
|
+
type: "object",
|
|
101
|
+
properties: {
|
|
102
|
+
// rule options
|
|
103
|
+
},
|
|
104
|
+
additionalProperties: false,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
messages: {
|
|
108
|
+
missingStory: "Function '{{name}}' is missing @story annotation",
|
|
109
|
+
invalidStoryFormat: "@story annotation format is invalid: {{format}}",
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
create(context) {
|
|
113
|
+
return {
|
|
114
|
+
FunctionDeclaration(node) {
|
|
115
|
+
// rule implementation
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Rule Implementation Guidelines
|
|
125
|
+
|
|
126
|
+
1. **Use TypeScript for type safety**: Leverage @typescript-eslint/utils for AST manipulation
|
|
127
|
+
2. **Clear error messages**: Provide helpful, actionable error messages
|
|
128
|
+
3. **Configurable options**: Allow users to customize rule behavior
|
|
129
|
+
4. **Performance**: Avoid expensive operations in visitors
|
|
130
|
+
5. **Testing**: Use ESLint's RuleTester for comprehensive testing
|
|
131
|
+
|
|
132
|
+
### AST Node Handling
|
|
133
|
+
|
|
134
|
+
When working with AST nodes, use TypeScript for safety:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { TSESTree } from "@typescript-eslint/utils";
|
|
138
|
+
|
|
139
|
+
function checkFunctionAnnotation(node: TSESTree.FunctionDeclaration) {
|
|
140
|
+
// Type-safe AST manipulation
|
|
141
|
+
if (node.id?.name) {
|
|
142
|
+
// Check for @story annotation in comments
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Configuration Presets
|
|
148
|
+
|
|
149
|
+
### Recommended Configuration
|
|
150
|
+
|
|
151
|
+
Provide a recommended configuration for common use cases:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
const plugin = {
|
|
155
|
+
// ... meta and rules
|
|
156
|
+
configs: {},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Assign configs after plugin definition to reference plugin
|
|
160
|
+
Object.assign(plugin.configs, {
|
|
161
|
+
recommended: [
|
|
162
|
+
{
|
|
163
|
+
plugins: {
|
|
164
|
+
traceability: plugin,
|
|
165
|
+
},
|
|
166
|
+
rules: {
|
|
167
|
+
"traceability/require-story-annotation": "error",
|
|
168
|
+
"traceability/require-req-annotation": "error",
|
|
169
|
+
"traceability/valid-story-reference": "error",
|
|
170
|
+
"traceability/valid-req-reference": "error",
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
strict: [
|
|
175
|
+
{
|
|
176
|
+
plugins: {
|
|
177
|
+
traceability: plugin,
|
|
178
|
+
},
|
|
179
|
+
rules: {
|
|
180
|
+
"traceability/require-story-annotation": "error",
|
|
181
|
+
"traceability/require-req-annotation": "error",
|
|
182
|
+
"traceability/valid-story-reference": "error",
|
|
183
|
+
"traceability/valid-req-reference": "error",
|
|
184
|
+
"traceability/require-branch-annotation": "error",
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Configuration Usage
|
|
192
|
+
|
|
193
|
+
Users can extend configurations in their eslint.config.js:
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
// eslint.config.js
|
|
197
|
+
import { defineConfig } from "eslint/config";
|
|
198
|
+
import traceability from "eslint-plugin-traceability";
|
|
199
|
+
|
|
200
|
+
export default defineConfig([
|
|
201
|
+
{
|
|
202
|
+
files: ["src/**/*.{js,ts}"],
|
|
203
|
+
plugins: {
|
|
204
|
+
traceability,
|
|
205
|
+
},
|
|
206
|
+
extends: ["traceability/recommended"],
|
|
207
|
+
},
|
|
208
|
+
]);
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Testing Strategy
|
|
212
|
+
|
|
213
|
+
### Using ESLint's RuleTester
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
// tests/rules/require-story-annotation.test.ts
|
|
217
|
+
import { RuleTester } from "eslint";
|
|
218
|
+
import rule from "../../src/rules/require-story-annotation";
|
|
219
|
+
|
|
220
|
+
const ruleTester = new RuleTester({
|
|
221
|
+
parser: require.resolve("@typescript-eslint/parser"),
|
|
222
|
+
parserOptions: {
|
|
223
|
+
ecmaVersion: 2020,
|
|
224
|
+
sourceType: "module",
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
ruleTester.run("require-story-annotation", rule, {
|
|
229
|
+
valid: [
|
|
230
|
+
{
|
|
231
|
+
code: `
|
|
232
|
+
/**
|
|
233
|
+
* @story docs/stories/001.0-DEV-EXAMPLE.story.md
|
|
234
|
+
* @req REQ-EXAMPLE
|
|
235
|
+
*/
|
|
236
|
+
function validFunction() {}
|
|
237
|
+
`,
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
invalid: [
|
|
241
|
+
{
|
|
242
|
+
code: `function invalidFunction() {}`,
|
|
243
|
+
errors: [
|
|
244
|
+
{
|
|
245
|
+
messageId: "missingStory",
|
|
246
|
+
data: { name: "invalidFunction" },
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Test Organization
|
|
255
|
+
|
|
256
|
+
- **Unit tests**: Test individual rules in isolation
|
|
257
|
+
- **Integration tests**: Test plugin loading and configuration
|
|
258
|
+
- **File system tests**: Test file reference validation (use temporary directories)
|
|
259
|
+
|
|
260
|
+
## Project-Specific Considerations
|
|
261
|
+
|
|
262
|
+
### File System Integration
|
|
263
|
+
|
|
264
|
+
For validating @story references to actual files:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import fs from "fs/promises";
|
|
268
|
+
import path from "path";
|
|
269
|
+
|
|
270
|
+
async function validateStoryFile(
|
|
271
|
+
storyPath: string,
|
|
272
|
+
context: any,
|
|
273
|
+
): Promise<boolean> {
|
|
274
|
+
try {
|
|
275
|
+
const fullPath = path.resolve(context.getCwd(), storyPath);
|
|
276
|
+
|
|
277
|
+
// Check file exists
|
|
278
|
+
await fs.access(fullPath);
|
|
279
|
+
|
|
280
|
+
// Check file extension
|
|
281
|
+
if (!fullPath.endsWith(".story.md")) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return true;
|
|
286
|
+
} catch {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Requirement Reference Validation
|
|
293
|
+
|
|
294
|
+
For validating @req references within story files:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
async function validateRequirement(
|
|
298
|
+
storyPath: string,
|
|
299
|
+
reqId: string,
|
|
300
|
+
): Promise<boolean> {
|
|
301
|
+
try {
|
|
302
|
+
const content = await fs.readFile(storyPath, "utf8");
|
|
303
|
+
|
|
304
|
+
// Look for requirement ID in story content
|
|
305
|
+
const reqPattern = new RegExp(`\\*\\*${reqId}\\*\\*:`, "g");
|
|
306
|
+
return reqPattern.test(content);
|
|
307
|
+
} catch {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Configuration Options
|
|
314
|
+
|
|
315
|
+
Allow users to customize behavior:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
interface RuleOptions {
|
|
319
|
+
storyFilePattern?: string; // Default: "**/*.story.md"
|
|
320
|
+
requirementPattern?: string; // Default: "REQ-*"
|
|
321
|
+
excludePatterns?: string[]; // Files to exclude
|
|
322
|
+
includePrivateFunctions?: boolean; // Default: false
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Build and Distribution
|
|
327
|
+
|
|
328
|
+
### TypeScript Configuration
|
|
329
|
+
|
|
330
|
+
Configure TypeScript to output CommonJS for ESLint compatibility:
|
|
331
|
+
|
|
332
|
+
```json
|
|
333
|
+
// tsconfig.json
|
|
334
|
+
{
|
|
335
|
+
"compilerOptions": {
|
|
336
|
+
"target": "ES2020",
|
|
337
|
+
"module": "commonjs",
|
|
338
|
+
"moduleResolution": "node",
|
|
339
|
+
"declaration": true,
|
|
340
|
+
"outDir": "./lib",
|
|
341
|
+
"strict": true
|
|
342
|
+
},
|
|
343
|
+
"include": ["src/**/*"],
|
|
344
|
+
"exclude": ["node_modules", "lib", "tests"]
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Package.json Configuration
|
|
349
|
+
|
|
350
|
+
Essential package.json settings for ESLint plugins:
|
|
351
|
+
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"name": "eslint-plugin-traceability",
|
|
355
|
+
"version": "1.0.0",
|
|
356
|
+
"description": "ESLint plugin for enforcing code traceability annotations",
|
|
357
|
+
"main": "lib/index.js",
|
|
358
|
+
"types": "lib/index.d.ts",
|
|
359
|
+
"keywords": ["eslint", "eslintplugin", "eslint-plugin", "traceability"],
|
|
360
|
+
"peerDependencies": {
|
|
361
|
+
"eslint": ">=9.0.0"
|
|
362
|
+
},
|
|
363
|
+
"engines": {
|
|
364
|
+
"node": ">=18.0.0"
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## Development Workflow
|
|
370
|
+
|
|
371
|
+
### Local Testing
|
|
372
|
+
|
|
373
|
+
1. **Link locally**: Use `npm link` for local development
|
|
374
|
+
2. **Test project**: Create a test project to verify plugin behavior
|
|
375
|
+
3. **Rule tester**: Use ESLint's RuleTester for individual rule testing
|
|
376
|
+
4. **Integration testing**: Test complete plugin configuration
|
|
377
|
+
|
|
378
|
+
### Quality Checks
|
|
379
|
+
|
|
380
|
+
Recommended linting for the plugin itself:
|
|
381
|
+
|
|
382
|
+
```javascript
|
|
383
|
+
// eslint.config.js (for the plugin project)
|
|
384
|
+
import js from "@eslint/js";
|
|
385
|
+
import typescript from "@typescript-eslint/eslint-plugin";
|
|
386
|
+
import eslintPlugin from "eslint-plugin-eslint-plugin";
|
|
387
|
+
|
|
388
|
+
export default [
|
|
389
|
+
js.configs.recommended,
|
|
390
|
+
{
|
|
391
|
+
plugins: {
|
|
392
|
+
"@typescript-eslint": typescript,
|
|
393
|
+
"eslint-plugin": eslintPlugin,
|
|
394
|
+
},
|
|
395
|
+
rules: {
|
|
396
|
+
// Plugin-specific linting rules
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
];
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Performance Considerations
|
|
403
|
+
|
|
404
|
+
### Efficient AST Traversal
|
|
405
|
+
|
|
406
|
+
- **Minimal visitors**: Only register for needed node types
|
|
407
|
+
- **Early returns**: Exit early when conditions aren't met
|
|
408
|
+
- **Caching**: Cache expensive operations (file reads, regex compilation)
|
|
409
|
+
- **Async handling**: Use proper async patterns for file operations
|
|
410
|
+
|
|
411
|
+
### Memory Management
|
|
412
|
+
|
|
413
|
+
- **Avoid global state**: Keep rule instances isolated
|
|
414
|
+
- **Clean up resources**: Properly handle file handles and timers
|
|
415
|
+
- **Limit recursion**: Avoid deep recursive operations
|
|
416
|
+
|
|
417
|
+
## Documentation Requirements
|
|
418
|
+
|
|
419
|
+
### Rule Documentation
|
|
420
|
+
|
|
421
|
+
Each rule should have comprehensive documentation:
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
const rule = {
|
|
425
|
+
meta: {
|
|
426
|
+
docs: {
|
|
427
|
+
description: "require @story annotations on functions",
|
|
428
|
+
category: "Traceability",
|
|
429
|
+
recommended: true,
|
|
430
|
+
url: "https://github.com/voder-ai/eslint-plugin-traceability#require-story-annotation",
|
|
431
|
+
},
|
|
432
|
+
// ... other meta properties
|
|
433
|
+
},
|
|
434
|
+
// ... rule implementation
|
|
435
|
+
};
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### README Structure
|
|
439
|
+
|
|
440
|
+
Include in the plugin README:
|
|
441
|
+
|
|
442
|
+
1. **Installation instructions**
|
|
443
|
+
2. **Configuration examples**
|
|
444
|
+
3. **Rule documentation**
|
|
445
|
+
4. **Usage examples**
|
|
446
|
+
5. **Troubleshooting guide**
|
|
447
|
+
|
|
448
|
+
## Security Considerations
|
|
449
|
+
|
|
450
|
+
### File System Access
|
|
451
|
+
|
|
452
|
+
- **Validate paths**: Prevent directory traversal attacks
|
|
453
|
+
- **Sanitize input**: Validate user-provided file patterns
|
|
454
|
+
- **Limit scope**: Restrict file access to project directory
|
|
455
|
+
|
|
456
|
+
### Input Validation
|
|
457
|
+
|
|
458
|
+
- **Schema validation**: Use JSON Schema for rule options
|
|
459
|
+
- **Type checking**: Leverage TypeScript for compile-time safety
|
|
460
|
+
- **Runtime checks**: Validate configuration at runtime
|
|
461
|
+
|
|
462
|
+
## Maintenance Guidelines
|
|
463
|
+
|
|
464
|
+
### Version Management
|
|
465
|
+
|
|
466
|
+
- **Semantic versioning**: Follow semver for releases
|
|
467
|
+
- **Breaking changes**: Document breaking changes clearly
|
|
468
|
+
- **Migration guides**: Provide upgrade instructions
|
|
469
|
+
|
|
470
|
+
### Community Support
|
|
471
|
+
|
|
472
|
+
- **Issue templates**: Provide clear bug report templates
|
|
473
|
+
- **Contributing guide**: Document contribution process
|
|
474
|
+
- **Code of conduct**: Establish community guidelines
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
### Security and Dependency Tooling
|
|
479
|
+
|
|
480
|
+
Plugin development in this repo is protected by the same security and dependency checks described in the main README. `npm run ci-verify:full` runs `npm audit --omit=dev --audit-level=high`, `npm run safety:deps`, and `npm run audit:dev-high`. These commands are executed both locally via Husky pre-push hooks and in CI, so contributors working on rules or plugin internals automatically benefit from the same security and dependency guarantees promised to end users.
|
|
481
|
+
|
|
482
|
+
## Related Resources
|
|
483
|
+
|
|
484
|
+
- [ESLint Plugin Development Guide](https://eslint.org/docs/latest/extend/plugins)
|
|
485
|
+
- [ESLint Custom Rules](https://eslint.org/docs/latest/extend/custom-rules)
|
|
486
|
+
- [@typescript-eslint/utils](https://typescript-eslint.io/packages/utils/)
|
|
487
|
+
- [ESLint RuleTester](https://eslint.org/docs/latest/integrate/nodejs-api#ruletester)
|