awesome-slash 2.4.2

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.
Files changed (95) hide show
  1. package/.claude-plugin/marketplace.json +54 -0
  2. package/.claude-plugin/plugin.json +11 -0
  3. package/.mcp.json +8 -0
  4. package/CHANGELOG.md +261 -0
  5. package/LICENSE +21 -0
  6. package/README.md +363 -0
  7. package/SECURITY.md +101 -0
  8. package/adapters/README.md +256 -0
  9. package/adapters/codex/README.md +272 -0
  10. package/adapters/codex/install.sh +179 -0
  11. package/adapters/opencode/README.md +301 -0
  12. package/adapters/opencode/install.sh +223 -0
  13. package/lib/patterns/review-patterns.js +511 -0
  14. package/lib/patterns/slop-patterns.js +647 -0
  15. package/lib/platform/detect-platform.js +535 -0
  16. package/lib/platform/verify-tools.js +235 -0
  17. package/lib/state/workflow-state.js +635 -0
  18. package/lib/state/workflow-state.schema.json +282 -0
  19. package/lib/utils/context-optimizer.js +227 -0
  20. package/mcp-server/index.js +303 -0
  21. package/mcp-server/package.json +23 -0
  22. package/package.json +63 -0
  23. package/plugins/deslop-around/.claude-plugin/plugin.json +20 -0
  24. package/plugins/deslop-around/commands/deslop-around.md +220 -0
  25. package/plugins/deslop-around/lib/patterns/review-patterns.js +511 -0
  26. package/plugins/deslop-around/lib/patterns/slop-patterns.js +641 -0
  27. package/plugins/deslop-around/lib/platform/detect-platform.js +514 -0
  28. package/plugins/deslop-around/lib/platform/verify-tools.js +235 -0
  29. package/plugins/deslop-around/lib/state/workflow-state.js +635 -0
  30. package/plugins/deslop-around/lib/state/workflow-state.schema.json +282 -0
  31. package/plugins/deslop-around/lib/utils/context-optimizer.js +222 -0
  32. package/plugins/next-task/.claude-plugin/plugin.json +24 -0
  33. package/plugins/next-task/agents/ci-fixer.md +236 -0
  34. package/plugins/next-task/agents/ci-monitor.md +291 -0
  35. package/plugins/next-task/agents/delivery-validator.md +451 -0
  36. package/plugins/next-task/agents/deslop-work.md +272 -0
  37. package/plugins/next-task/agents/docs-updater.md +506 -0
  38. package/plugins/next-task/agents/exploration-agent.md +277 -0
  39. package/plugins/next-task/agents/implementation-agent.md +427 -0
  40. package/plugins/next-task/agents/planning-agent.md +236 -0
  41. package/plugins/next-task/agents/policy-selector.md +248 -0
  42. package/plugins/next-task/agents/review-orchestrator.md +521 -0
  43. package/plugins/next-task/agents/simple-fixer.md +136 -0
  44. package/plugins/next-task/agents/task-discoverer.md +357 -0
  45. package/plugins/next-task/agents/test-coverage-checker.md +447 -0
  46. package/plugins/next-task/agents/worktree-manager.md +419 -0
  47. package/plugins/next-task/commands/delivery-approval.md +331 -0
  48. package/plugins/next-task/commands/next-task.md +627 -0
  49. package/plugins/next-task/commands/update-docs-around.md +418 -0
  50. package/plugins/next-task/hooks/hooks.json +14 -0
  51. package/plugins/next-task/lib/patterns/review-patterns.js +511 -0
  52. package/plugins/next-task/lib/patterns/slop-patterns.js +641 -0
  53. package/plugins/next-task/lib/platform/detect-platform.js +514 -0
  54. package/plugins/next-task/lib/platform/verify-tools.js +235 -0
  55. package/plugins/next-task/lib/state/tasks-registry.schema.json +85 -0
  56. package/plugins/next-task/lib/state/workflow-state.js +635 -0
  57. package/plugins/next-task/lib/state/workflow-state.schema.json +282 -0
  58. package/plugins/next-task/lib/state/worktree-status.schema.json +219 -0
  59. package/plugins/next-task/lib/utils/context-optimizer.js +222 -0
  60. package/plugins/project-review/.claude-plugin/plugin.json +20 -0
  61. package/plugins/project-review/commands/project-review-agents.md +286 -0
  62. package/plugins/project-review/commands/project-review-github.md +142 -0
  63. package/plugins/project-review/commands/project-review.md +273 -0
  64. package/plugins/project-review/lib/patterns/review-patterns.js +511 -0
  65. package/plugins/project-review/lib/patterns/slop-patterns.js +641 -0
  66. package/plugins/project-review/lib/platform/detect-platform.js +514 -0
  67. package/plugins/project-review/lib/platform/verify-tools.js +235 -0
  68. package/plugins/project-review/lib/state/workflow-state.js +635 -0
  69. package/plugins/project-review/lib/state/workflow-state.schema.json +282 -0
  70. package/plugins/project-review/lib/utils/context-optimizer.js +222 -0
  71. package/plugins/reality-check/.claude-plugin/plugin.json +23 -0
  72. package/plugins/reality-check/README.md +156 -0
  73. package/plugins/reality-check/agents/code-explorer.md +353 -0
  74. package/plugins/reality-check/agents/doc-analyzer.md +337 -0
  75. package/plugins/reality-check/agents/issue-scanner.md +231 -0
  76. package/plugins/reality-check/agents/plan-synthesizer.md +479 -0
  77. package/plugins/reality-check/commands/scan.md +242 -0
  78. package/plugins/reality-check/commands/set.md +203 -0
  79. package/plugins/reality-check/lib/state/reality-check-state.js +509 -0
  80. package/plugins/reality-check/skills/reality-analysis/SKILL.md +317 -0
  81. package/plugins/ship/.claude-plugin/plugin.json +21 -0
  82. package/plugins/ship/commands/ship-ci-review-loop.md +443 -0
  83. package/plugins/ship/commands/ship-deployment.md +330 -0
  84. package/plugins/ship/commands/ship-error-handling.md +254 -0
  85. package/plugins/ship/commands/ship.md +370 -0
  86. package/plugins/ship/lib/patterns/review-patterns.js +511 -0
  87. package/plugins/ship/lib/patterns/slop-patterns.js +641 -0
  88. package/plugins/ship/lib/platform/detect-platform.js +514 -0
  89. package/plugins/ship/lib/platform/verify-tools.js +235 -0
  90. package/plugins/ship/lib/state/workflow-state.js +635 -0
  91. package/plugins/ship/lib/state/workflow-state.schema.json +282 -0
  92. package/plugins/ship/lib/utils/context-optimizer.js +222 -0
  93. package/scripts/install/claude.sh +50 -0
  94. package/scripts/install/codex.sh +181 -0
  95. package/scripts/install/opencode.sh +211 -0
@@ -0,0 +1,641 @@
1
+ /**
2
+ * Slop Detection Patterns
3
+ * Pattern library for detecting and removing AI-generated code slop
4
+ *
5
+ * @author Avi Fenesh
6
+ * @license MIT
7
+ */
8
+
9
+ /**
10
+ * Deep freeze an object for V8 optimization and immutability
11
+ * @param {Object} obj - Object to freeze
12
+ * @returns {Object} Frozen object
13
+ */
14
+ function deepFreeze(obj) {
15
+ Object.keys(obj).forEach(key => {
16
+ if (typeof obj[key] === 'object' && obj[key] !== null && !(obj[key] instanceof RegExp)) {
17
+ deepFreeze(obj[key]);
18
+ }
19
+ });
20
+ return Object.freeze(obj);
21
+ }
22
+
23
+ // Pre-compiled regex cache for performance
24
+ const _compiledExcludePatterns = new Map();
25
+
26
+ /**
27
+ * Get a compiled regex for an exclude pattern (cached)
28
+ * @param {string} pattern - Glob pattern to compile
29
+ * @returns {RegExp} Compiled regex
30
+ */
31
+ function getCompiledPattern(pattern) {
32
+ if (!_compiledExcludePatterns.has(pattern)) {
33
+ // Escape all regex metacharacters except *, then replace * with .*
34
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
35
+ const regexStr = '^' + escaped.replace(/\*/g, '.*') + '$';
36
+ _compiledExcludePatterns.set(pattern, new RegExp(regexStr));
37
+ }
38
+ return _compiledExcludePatterns.get(pattern);
39
+ }
40
+
41
+ /**
42
+ * Auto-fix strategies:
43
+ * - remove: Delete the matching line(s)
44
+ * - replace: Replace with suggested fix
45
+ * - add_logging: Add proper error logging
46
+ * - flag: Mark for manual review
47
+ * - none: Report only, no auto-fix
48
+ */
49
+
50
+ const slopPatterns = {
51
+ /**
52
+ * Console debugging in JavaScript/TypeScript
53
+ */
54
+ console_debugging: {
55
+ pattern: /console\.(log|debug|info|warn)\(/,
56
+ exclude: ['*.test.*', '*.spec.*', '*.config.*'],
57
+ severity: 'medium',
58
+ autoFix: 'remove',
59
+ language: 'javascript',
60
+ description: 'Console.log statements left in production code'
61
+ },
62
+
63
+ /**
64
+ * Python debugging statements
65
+ */
66
+ python_debugging: {
67
+ pattern: /(print\(|import pdb|breakpoint\(\)|import ipdb)/,
68
+ exclude: ['test_*.py', '*_test.py', 'conftest.py'],
69
+ severity: 'medium',
70
+ autoFix: 'remove',
71
+ language: 'python',
72
+ description: 'Debug print/breakpoint statements in production'
73
+ },
74
+
75
+ /**
76
+ * Rust debugging macros
77
+ */
78
+ rust_debugging: {
79
+ pattern: /(println!|dbg!|eprintln!)\(/,
80
+ exclude: ['*_test.rs', '*_tests.rs'],
81
+ severity: 'medium',
82
+ autoFix: 'remove',
83
+ language: 'rust',
84
+ description: 'Debug print macros in production code'
85
+ },
86
+
87
+ /**
88
+ * Old TODO comments (>90 days)
89
+ */
90
+ old_todos: {
91
+ pattern: /(TODO|FIXME|HACK|XXX):/,
92
+ exclude: [],
93
+ severity: 'low',
94
+ autoFix: 'flag',
95
+ language: null, // All languages
96
+ description: 'TODO/FIXME comments older than 90 days',
97
+ requiresAgeCheck: true,
98
+ ageThreshold: 90 // days
99
+ },
100
+
101
+ /**
102
+ * Commented out code blocks
103
+ */
104
+ commented_code: {
105
+ pattern: /^\s*(\/\/|#)\s*\w{5,}/,
106
+ exclude: [],
107
+ severity: 'medium',
108
+ autoFix: 'remove',
109
+ language: null,
110
+ description: 'Large blocks of commented-out code',
111
+ minConsecutiveLines: 5
112
+ },
113
+
114
+ /**
115
+ * Placeholder text
116
+ */
117
+ placeholder_text: {
118
+ pattern: /(lorem ipsum|test test test|asdf|foo bar baz|placeholder|replace this|todo: implement)/i,
119
+ exclude: ['*.test.*', '*.spec.*', 'README.*', '*.md'],
120
+ severity: 'high',
121
+ autoFix: 'flag',
122
+ language: null,
123
+ description: 'Placeholder text that should be replaced'
124
+ },
125
+
126
+ /**
127
+ * Empty catch blocks (JavaScript/TypeScript)
128
+ */
129
+ empty_catch_js: {
130
+ pattern: /catch\s*\([^)]*\)\s*\{\s*\}/,
131
+ exclude: [],
132
+ severity: 'high',
133
+ autoFix: 'add_logging',
134
+ language: 'javascript',
135
+ description: 'Empty catch blocks without error handling'
136
+ },
137
+
138
+ /**
139
+ * Empty except blocks (Python)
140
+ */
141
+ empty_except_py: {
142
+ pattern: /except\s*[^:]*:\s*pass\s*$/,
143
+ exclude: [],
144
+ severity: 'high',
145
+ autoFix: 'add_logging',
146
+ language: 'python',
147
+ description: 'Empty except blocks with just pass'
148
+ },
149
+
150
+ /**
151
+ * Magic numbers (large hardcoded numbers)
152
+ */
153
+ magic_numbers: {
154
+ pattern: /(?<![a-zA-Z_\d])[0-9]{4,}(?![a-zA-Z_\d])/,
155
+ exclude: ['*.test.*', '*.spec.*', '*.config.*', 'package.json', 'package-lock.json'],
156
+ severity: 'low',
157
+ autoFix: 'flag',
158
+ language: null,
159
+ description: 'Magic numbers that should be constants'
160
+ },
161
+
162
+ /**
163
+ * Disabled linter rules
164
+ */
165
+ disabled_linter: {
166
+ pattern: /(eslint-disable|pylint: disable|#\s*noqa|@SuppressWarnings|#\[allow\()/,
167
+ exclude: [],
168
+ severity: 'medium',
169
+ autoFix: 'flag',
170
+ language: null,
171
+ description: 'Disabled linter rules that may hide issues'
172
+ },
173
+
174
+ /**
175
+ * Unused imports (basic pattern, language-specific tools better)
176
+ */
177
+ unused_imports_hint: {
178
+ pattern: /^import .* from .* \/\/ unused$/,
179
+ exclude: [],
180
+ severity: 'low',
181
+ autoFix: 'remove',
182
+ language: null,
183
+ description: 'Imports marked as unused'
184
+ },
185
+
186
+ /**
187
+ * Duplicate string literals (same string >5 times)
188
+ */
189
+ duplicate_strings: {
190
+ pattern: null, // Requires multi-pass analysis
191
+ exclude: ['*.test.*', '*.spec.*'],
192
+ severity: 'low',
193
+ autoFix: 'flag',
194
+ language: null,
195
+ description: 'Duplicate string literals that should be constants',
196
+ requiresMultiPass: true
197
+ },
198
+
199
+ /**
200
+ * Inconsistent indentation markers
201
+ */
202
+ mixed_indentation: {
203
+ pattern: /^\t+ +|^ +\t+/,
204
+ exclude: ['Makefile', '*.mk'],
205
+ severity: 'low',
206
+ autoFix: 'replace',
207
+ language: null,
208
+ description: 'Mixed tabs and spaces'
209
+ },
210
+
211
+ /**
212
+ * Trailing whitespace
213
+ */
214
+ trailing_whitespace: {
215
+ pattern: /\s+$/,
216
+ exclude: ['*.md'], // Markdown uses trailing spaces for line breaks
217
+ severity: 'low',
218
+ autoFix: 'remove',
219
+ language: null,
220
+ description: 'Trailing whitespace at end of lines'
221
+ },
222
+
223
+ /**
224
+ * Multiple consecutive blank lines
225
+ */
226
+ multiple_blank_lines: {
227
+ pattern: /^\s*\n\s*\n\s*\n/,
228
+ exclude: [],
229
+ severity: 'low',
230
+ autoFix: 'replace',
231
+ language: null,
232
+ description: 'More than 2 consecutive blank lines'
233
+ },
234
+
235
+ /**
236
+ * Hardcoded credentials patterns (expanded for comprehensive detection)
237
+ */
238
+ hardcoded_secrets: {
239
+ pattern: /(password|secret|api[_-]?key|token|credential|auth)[_-]?(key|token|secret|pass)?\s*[:=]\s*["'`][^"'`\s]{8,}["'`]/i,
240
+ exclude: ['*.test.*', '*.spec.*', '*.example.*', '*.sample.*', 'README.*', '*.md'],
241
+ severity: 'critical',
242
+ autoFix: 'flag',
243
+ language: null,
244
+ description: 'Potential hardcoded credentials'
245
+ },
246
+
247
+ /**
248
+ * JWT tokens (eyJ prefix indicates base64 JSON header)
249
+ */
250
+ jwt_tokens: {
251
+ pattern: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/,
252
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
253
+ severity: 'critical',
254
+ autoFix: 'flag',
255
+ language: null,
256
+ description: 'Hardcoded JWT token'
257
+ },
258
+
259
+ /**
260
+ * OpenAI API keys (sk-... format)
261
+ */
262
+ openai_api_key: {
263
+ pattern: /sk-[a-zA-Z0-9]{32,}/,
264
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
265
+ severity: 'critical',
266
+ autoFix: 'flag',
267
+ language: null,
268
+ description: 'Hardcoded OpenAI API key'
269
+ },
270
+
271
+ /**
272
+ * GitHub tokens (personal access tokens, fine-grained tokens, OAuth)
273
+ */
274
+ github_token: {
275
+ pattern: /(ghp_[a-zA-Z0-9]{36}|gho_[a-zA-Z0-9]{36}|ghu_[a-zA-Z0-9]{36}|ghs_[a-zA-Z0-9]{36}|ghr_[a-zA-Z0-9]{36}|github_pat_[a-zA-Z0-9]{22}_[a-zA-Z0-9]{59})/,
276
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
277
+ severity: 'critical',
278
+ autoFix: 'flag',
279
+ language: null,
280
+ description: 'Hardcoded GitHub token'
281
+ },
282
+
283
+ /**
284
+ * AWS credentials (access key IDs and secret keys)
285
+ */
286
+ aws_credentials: {
287
+ pattern: /(AKIA[0-9A-Z]{16}|aws_secret_access_key\s*[:=]\s*["'`][A-Za-z0-9/+=]{40}["'`])/i,
288
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
289
+ severity: 'critical',
290
+ autoFix: 'flag',
291
+ language: null,
292
+ description: 'Hardcoded AWS credentials'
293
+ },
294
+
295
+ /**
296
+ * Google Cloud / Firebase API keys and service accounts
297
+ */
298
+ google_api_key: {
299
+ pattern: /(AIza[0-9A-Za-z_-]{35}|[0-9]+-[a-z0-9_]{32}\.apps\.googleusercontent\.com)/,
300
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
301
+ severity: 'critical',
302
+ autoFix: 'flag',
303
+ language: null,
304
+ description: 'Hardcoded Google/Firebase API key'
305
+ },
306
+
307
+ /**
308
+ * Stripe API keys (live and test)
309
+ */
310
+ stripe_api_key: {
311
+ pattern: /(sk_live_[a-zA-Z0-9]{24,}|sk_test_[a-zA-Z0-9]{24,}|rk_live_[a-zA-Z0-9]{24,}|rk_test_[a-zA-Z0-9]{24,})/,
312
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
313
+ severity: 'critical',
314
+ autoFix: 'flag',
315
+ language: null,
316
+ description: 'Hardcoded Stripe API key'
317
+ },
318
+
319
+ /**
320
+ * Slack tokens (bot, user, webhook)
321
+ */
322
+ slack_token: {
323
+ pattern: /(xoxb-[0-9]{10,}-[0-9]{10,}-[a-zA-Z0-9]{24}|xoxp-[0-9]{10,}-[0-9]{10,}-[a-zA-Z0-9]{24}|xoxa-[0-9]{10,}-[a-zA-Z0-9]{24}|https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]{8}\/B[A-Z0-9]{8,}\/[a-zA-Z0-9]{24})/,
324
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
325
+ severity: 'critical',
326
+ autoFix: 'flag',
327
+ language: null,
328
+ description: 'Hardcoded Slack token or webhook URL'
329
+ },
330
+
331
+ /**
332
+ * Discord tokens and webhook URLs
333
+ */
334
+ discord_token: {
335
+ pattern: /(discord.*["'`][A-Za-z0-9_-]{24}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27}["'`]|https:\/\/discord(?:app)?\.com\/api\/webhooks\/[0-9]+\/[A-Za-z0-9_-]+)/i,
336
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
337
+ severity: 'critical',
338
+ autoFix: 'flag',
339
+ language: null,
340
+ description: 'Hardcoded Discord token or webhook'
341
+ },
342
+
343
+ /**
344
+ * SendGrid API key
345
+ */
346
+ sendgrid_api_key: {
347
+ pattern: /SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}/,
348
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
349
+ severity: 'critical',
350
+ autoFix: 'flag',
351
+ language: null,
352
+ description: 'Hardcoded SendGrid API key'
353
+ },
354
+
355
+ /**
356
+ * Twilio credentials
357
+ */
358
+ twilio_credentials: {
359
+ pattern: /(AC[a-f0-9]{32}|SK[a-f0-9]{32})/,
360
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
361
+ severity: 'critical',
362
+ autoFix: 'flag',
363
+ language: null,
364
+ description: 'Hardcoded Twilio credentials'
365
+ },
366
+
367
+ /**
368
+ * NPM tokens
369
+ */
370
+ npm_token: {
371
+ pattern: /npm_[a-zA-Z0-9]{36}/,
372
+ exclude: ['*.test.*', '*.spec.*', '*.example.*'],
373
+ severity: 'critical',
374
+ autoFix: 'flag',
375
+ language: null,
376
+ description: 'Hardcoded NPM token'
377
+ },
378
+
379
+ /**
380
+ * Private keys (RSA, DSA, EC, PGP)
381
+ */
382
+ private_key: {
383
+ pattern: /-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/,
384
+ exclude: ['*.test.*', '*.spec.*', '*.example.*', '*.pem.example'],
385
+ severity: 'critical',
386
+ autoFix: 'flag',
387
+ language: null,
388
+ description: 'Private key in source code'
389
+ },
390
+
391
+ /**
392
+ * Generic high-entropy strings (potential secrets)
393
+ */
394
+ high_entropy_string: {
395
+ pattern: /["'`][A-Za-z0-9+/=_-]{40,}["'`]/,
396
+ exclude: ['*.test.*', '*.spec.*', '*.example.*', '*.lock', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'],
397
+ severity: 'medium',
398
+ autoFix: 'flag',
399
+ language: null,
400
+ description: 'High-entropy string that may be a secret',
401
+ requiresEntropyCheck: true,
402
+ entropyThreshold: 4.5
403
+ },
404
+
405
+ /**
406
+ * Process.exit in libraries
407
+ */
408
+ process_exit: {
409
+ pattern: /process\.exit\(/,
410
+ exclude: ['*.test.*', 'cli.js', 'index.js', 'bin/*'],
411
+ severity: 'high',
412
+ autoFix: 'flag',
413
+ language: 'javascript',
414
+ description: 'process.exit() should not be in library code'
415
+ },
416
+
417
+ /**
418
+ * Bare URLs in code (should use constants)
419
+ */
420
+ bare_urls: {
421
+ pattern: /https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/,
422
+ exclude: ['*.test.*', '*.md', 'package.json', 'README.*'],
423
+ severity: 'low',
424
+ autoFix: 'flag',
425
+ language: null,
426
+ description: 'Hardcoded URLs that should be configuration'
427
+ }
428
+ };
429
+
430
+ // Freeze the patterns object for V8 optimization
431
+ deepFreeze(slopPatterns);
432
+
433
+ // ============================================================================
434
+ // Pre-indexed Maps for O(1) lookup performance (#18)
435
+ // Built once at module load time, avoiding iteration on every lookup
436
+ // ============================================================================
437
+
438
+ /**
439
+ * Pre-indexed patterns by language
440
+ * Key: language name (or 'universal' for language-agnostic patterns)
441
+ * Value: Object of pattern name -> pattern definition
442
+ */
443
+ const _patternsByLanguage = new Map();
444
+
445
+ /**
446
+ * Pre-indexed patterns by severity
447
+ * Key: severity level ('critical', 'high', 'medium', 'low')
448
+ * Value: Object of pattern name -> pattern definition
449
+ */
450
+ const _patternsBySeverity = new Map();
451
+
452
+ /**
453
+ * Pre-indexed patterns by autoFix strategy
454
+ * Key: autoFix type ('remove', 'replace', 'add_logging', 'flag', 'none')
455
+ * Value: Object of pattern name -> pattern definition
456
+ */
457
+ const _patternsByAutoFix = new Map();
458
+
459
+ /**
460
+ * Set of all available languages for O(1) existence check
461
+ */
462
+ const _availableLanguages = new Set();
463
+
464
+ /**
465
+ * Set of all available severity levels for O(1) existence check
466
+ */
467
+ const _availableSeverities = new Set();
468
+
469
+ // Build indexes at module load time
470
+ (function buildIndexes() {
471
+ for (const [name, pattern] of Object.entries(slopPatterns)) {
472
+ // Index by language
473
+ const lang = pattern.language || 'universal';
474
+ if (!_patternsByLanguage.has(lang)) {
475
+ _patternsByLanguage.set(lang, {});
476
+ }
477
+ _patternsByLanguage.get(lang)[name] = pattern;
478
+ _availableLanguages.add(lang);
479
+
480
+ // Index by severity
481
+ const severity = pattern.severity;
482
+ if (!_patternsBySeverity.has(severity)) {
483
+ _patternsBySeverity.set(severity, {});
484
+ }
485
+ _patternsBySeverity.get(severity)[name] = pattern;
486
+ _availableSeverities.add(severity);
487
+
488
+ // Index by autoFix strategy
489
+ const autoFix = pattern.autoFix || 'none';
490
+ if (!_patternsByAutoFix.has(autoFix)) {
491
+ _patternsByAutoFix.set(autoFix, {});
492
+ }
493
+ _patternsByAutoFix.get(autoFix)[name] = pattern;
494
+ }
495
+ })();
496
+
497
+ // Freeze the index Sets
498
+ Object.freeze(_availableLanguages);
499
+ Object.freeze(_availableSeverities);
500
+
501
+ /**
502
+ * Get patterns for a specific language (O(1) lookup via pre-indexed Map)
503
+ * Includes universal patterns that apply to all languages
504
+ * @param {string} language - Language identifier ('javascript', 'python', 'rust', etc.)
505
+ * @returns {Object} Filtered patterns (language-specific + universal)
506
+ */
507
+ function getPatternsForLanguage(language) {
508
+ const langPatterns = _patternsByLanguage.get(language) || {};
509
+ const universalPatterns = _patternsByLanguage.get('universal') || {};
510
+
511
+ // Merge language-specific with universal patterns
512
+ return { ...universalPatterns, ...langPatterns };
513
+ }
514
+
515
+ /**
516
+ * Get patterns for a specific language only (excludes universal patterns)
517
+ * @param {string} language - Language identifier
518
+ * @returns {Object} Language-specific patterns only
519
+ */
520
+ function getPatternsForLanguageOnly(language) {
521
+ return _patternsByLanguage.get(language) || {};
522
+ }
523
+
524
+ /**
525
+ * Get universal patterns (apply to all languages)
526
+ * @returns {Object} Universal patterns
527
+ */
528
+ function getUniversalPatterns() {
529
+ return _patternsByLanguage.get('universal') || {};
530
+ }
531
+
532
+ /**
533
+ * Get patterns by severity (O(1) lookup via pre-indexed Map)
534
+ * @param {string} severity - Severity level ('critical', 'high', 'medium', 'low')
535
+ * @returns {Object} Filtered patterns
536
+ */
537
+ function getPatternsBySeverity(severity) {
538
+ return _patternsBySeverity.get(severity) || {};
539
+ }
540
+
541
+ /**
542
+ * Get patterns by autoFix strategy (O(1) lookup via pre-indexed Map)
543
+ * @param {string} autoFix - AutoFix strategy ('remove', 'replace', 'add_logging', 'flag', 'none')
544
+ * @returns {Object} Filtered patterns
545
+ */
546
+ function getPatternsByAutoFix(autoFix) {
547
+ return _patternsByAutoFix.get(autoFix) || {};
548
+ }
549
+
550
+ /**
551
+ * Get patterns matching multiple criteria (language AND severity)
552
+ * @param {Object} criteria - Filter criteria
553
+ * @param {string} [criteria.language] - Language filter
554
+ * @param {string} [criteria.severity] - Severity filter
555
+ * @param {string} [criteria.autoFix] - AutoFix strategy filter
556
+ * @returns {Object} Patterns matching all criteria
557
+ */
558
+ function getPatternsByCriteria(criteria = {}) {
559
+ let result = { ...slopPatterns };
560
+
561
+ if (criteria.language) {
562
+ const langPatterns = getPatternsForLanguage(criteria.language);
563
+ result = Object.fromEntries(
564
+ Object.entries(result).filter(([name]) => name in langPatterns)
565
+ );
566
+ }
567
+
568
+ if (criteria.severity) {
569
+ const severityPatterns = getPatternsBySeverity(criteria.severity);
570
+ result = Object.fromEntries(
571
+ Object.entries(result).filter(([name]) => name in severityPatterns)
572
+ );
573
+ }
574
+
575
+ if (criteria.autoFix) {
576
+ const autoFixPatterns = getPatternsByAutoFix(criteria.autoFix);
577
+ result = Object.fromEntries(
578
+ Object.entries(result).filter(([name]) => name in autoFixPatterns)
579
+ );
580
+ }
581
+
582
+ return result;
583
+ }
584
+
585
+ /**
586
+ * Get all available languages
587
+ * @returns {Array<string>} List of language identifiers
588
+ */
589
+ function getAvailableLanguages() {
590
+ return Array.from(_availableLanguages);
591
+ }
592
+
593
+ /**
594
+ * Get all available severity levels
595
+ * @returns {Array<string>} List of severity levels
596
+ */
597
+ function getAvailableSeverities() {
598
+ return Array.from(_availableSeverities);
599
+ }
600
+
601
+ /**
602
+ * Check if patterns exist for a language
603
+ * @param {string} language - Language identifier
604
+ * @returns {boolean} True if patterns exist
605
+ */
606
+ function hasLanguage(language) {
607
+ return _patternsByLanguage.has(language);
608
+ }
609
+
610
+ /**
611
+ * Check if a file should be excluded based on pattern rules
612
+ * Uses pre-compiled regex cache for performance
613
+ * @param {string} filePath - File path to check
614
+ * @param {Array<string>} excludePatterns - Exclude patterns
615
+ * @returns {boolean} True if file should be excluded
616
+ */
617
+ function isFileExcluded(filePath, excludePatterns) {
618
+ if (!excludePatterns || excludePatterns.length === 0) return false;
619
+
620
+ return excludePatterns.some(pattern => {
621
+ const regex = getCompiledPattern(pattern);
622
+ return regex.test(filePath);
623
+ });
624
+ }
625
+
626
+ module.exports = {
627
+ slopPatterns,
628
+ // Pre-indexed lookup functions (O(1) performance)
629
+ getPatternsForLanguage,
630
+ getPatternsForLanguageOnly,
631
+ getUniversalPatterns,
632
+ getPatternsBySeverity,
633
+ getPatternsByAutoFix,
634
+ getPatternsByCriteria,
635
+ // Metadata functions
636
+ getAvailableLanguages,
637
+ getAvailableSeverities,
638
+ hasLanguage,
639
+ // File exclusion
640
+ isFileExcluded
641
+ };