driftdetect 0.4.6 → 0.5.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.
Files changed (82) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bin/drift.js +27 -1
  3. package/dist/bin/drift.js.map +1 -1
  4. package/dist/commands/approve.d.ts +20 -0
  5. package/dist/commands/approve.d.ts.map +1 -1
  6. package/dist/commands/approve.js +38 -72
  7. package/dist/commands/approve.js.map +1 -1
  8. package/dist/commands/callgraph.js +4 -4
  9. package/dist/commands/callgraph.js.map +1 -1
  10. package/dist/commands/check.d.ts +41 -0
  11. package/dist/commands/check.d.ts.map +1 -1
  12. package/dist/commands/check.js +21 -11
  13. package/dist/commands/check.js.map +1 -1
  14. package/dist/commands/coupling.d.ts +17 -0
  15. package/dist/commands/coupling.d.ts.map +1 -0
  16. package/dist/commands/coupling.js +726 -0
  17. package/dist/commands/coupling.js.map +1 -0
  18. package/dist/commands/error-handling.d.ts +15 -0
  19. package/dist/commands/error-handling.d.ts.map +1 -0
  20. package/dist/commands/error-handling.js +608 -0
  21. package/dist/commands/error-handling.js.map +1 -0
  22. package/dist/commands/export.d.ts +16 -0
  23. package/dist/commands/export.d.ts.map +1 -1
  24. package/dist/commands/export.js +46 -50
  25. package/dist/commands/export.js.map +1 -1
  26. package/dist/commands/files.d.ts +15 -0
  27. package/dist/commands/files.d.ts.map +1 -1
  28. package/dist/commands/files.js +27 -48
  29. package/dist/commands/files.js.map +1 -1
  30. package/dist/commands/ignore.d.ts +20 -0
  31. package/dist/commands/ignore.d.ts.map +1 -1
  32. package/dist/commands/ignore.js +25 -48
  33. package/dist/commands/ignore.js.map +1 -1
  34. package/dist/commands/index.d.ts +6 -0
  35. package/dist/commands/index.d.ts.map +1 -1
  36. package/dist/commands/index.js +7 -0
  37. package/dist/commands/index.js.map +1 -1
  38. package/dist/commands/migrate-storage.d.ts +23 -0
  39. package/dist/commands/migrate-storage.d.ts.map +1 -0
  40. package/dist/commands/migrate-storage.js +337 -0
  41. package/dist/commands/migrate-storage.js.map +1 -0
  42. package/dist/commands/report.d.ts +22 -0
  43. package/dist/commands/report.d.ts.map +1 -1
  44. package/dist/commands/report.js +19 -10
  45. package/dist/commands/report.js.map +1 -1
  46. package/dist/commands/scan.d.ts +37 -0
  47. package/dist/commands/scan.d.ts.map +1 -1
  48. package/dist/commands/scan.js +233 -8
  49. package/dist/commands/scan.js.map +1 -1
  50. package/dist/commands/skills.d.ts +16 -0
  51. package/dist/commands/skills.d.ts.map +1 -0
  52. package/dist/commands/skills.js +409 -0
  53. package/dist/commands/skills.js.map +1 -0
  54. package/dist/commands/status.d.ts +20 -0
  55. package/dist/commands/status.d.ts.map +1 -1
  56. package/dist/commands/status.js +74 -72
  57. package/dist/commands/status.js.map +1 -1
  58. package/dist/commands/test-topology.d.ts +15 -0
  59. package/dist/commands/test-topology.d.ts.map +1 -0
  60. package/dist/commands/test-topology.js +589 -0
  61. package/dist/commands/test-topology.js.map +1 -0
  62. package/dist/commands/where.d.ts +15 -0
  63. package/dist/commands/where.d.ts.map +1 -1
  64. package/dist/commands/where.js +41 -88
  65. package/dist/commands/where.js.map +1 -1
  66. package/dist/commands/wrappers.d.ts +16 -0
  67. package/dist/commands/wrappers.d.ts.map +1 -0
  68. package/dist/commands/wrappers.js +181 -0
  69. package/dist/commands/wrappers.js.map +1 -0
  70. package/dist/services/pattern-service-factory.d.ts +37 -0
  71. package/dist/services/pattern-service-factory.d.ts.map +1 -0
  72. package/dist/services/pattern-service-factory.js +41 -0
  73. package/dist/services/pattern-service-factory.js.map +1 -0
  74. package/dist/services/scanner-service.d.ts +210 -0
  75. package/dist/services/scanner-service.d.ts.map +1 -1
  76. package/dist/services/scanner-service.js +298 -102
  77. package/dist/services/scanner-service.js.map +1 -1
  78. package/dist/workers/detector-worker.d.ts +107 -0
  79. package/dist/workers/detector-worker.d.ts.map +1 -0
  80. package/dist/workers/detector-worker.js +293 -0
  81. package/dist/workers/detector-worker.js.map +1 -0
  82. package/package.json +18 -17
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Scanner Service - Enterprise-grade pattern detection with Worker Threads
3
+ *
4
+ * Uses the real detectors from driftdetect-detectors to find
5
+ * high-value architectural patterns and violations.
6
+ *
7
+ * Now uses Piscina worker threads for parallel CPU-bound processing.
8
+ */
9
+ import { ManifestStore, type Manifest } from 'driftdetect-core';
10
+ /**
11
+ * Project-wide context for detection
12
+ */
13
+ export interface ProjectContext {
14
+ rootDir: string;
15
+ files: string[];
16
+ config: Record<string, unknown>;
17
+ }
18
+ /**
19
+ * Scanner service configuration
20
+ */
21
+ export interface ScannerServiceConfig {
22
+ rootDir: string;
23
+ verbose?: boolean;
24
+ categories?: string[];
25
+ /** Only run critical/high-value detectors */
26
+ criticalOnly?: boolean;
27
+ /** Enable manifest generation */
28
+ generateManifest?: boolean;
29
+ /** Only scan changed files (incremental) */
30
+ incremental?: boolean;
31
+ /** Use worker threads for parallel processing */
32
+ useWorkerThreads?: boolean;
33
+ /** Number of worker threads (default: CPU cores - 1) */
34
+ workerThreads?: number;
35
+ }
36
+ /**
37
+ * Aggregated pattern match across files
38
+ */
39
+ export interface AggregatedPattern {
40
+ patternId: string;
41
+ detectorId: string;
42
+ category: string;
43
+ subcategory: string;
44
+ name: string;
45
+ description: string;
46
+ locations: Array<{
47
+ file: string;
48
+ line: number;
49
+ column: number;
50
+ }>;
51
+ confidence: number;
52
+ occurrences: number;
53
+ }
54
+ /**
55
+ * Aggregated violation across files
56
+ */
57
+ export interface AggregatedViolation {
58
+ patternId: string;
59
+ detectorId: string;
60
+ category: string;
61
+ severity: 'error' | 'warning' | 'info' | 'hint';
62
+ file: string;
63
+ line: number;
64
+ column: number;
65
+ message: string;
66
+ explanation?: string | undefined;
67
+ suggestedFix?: string | undefined;
68
+ }
69
+ /**
70
+ * Scan result for a single file
71
+ */
72
+ export interface FileScanResult {
73
+ file: string;
74
+ patterns: Array<{
75
+ patternId: string;
76
+ detectorId: string;
77
+ confidence: number;
78
+ location: {
79
+ file: string;
80
+ line: number;
81
+ column: number;
82
+ };
83
+ }>;
84
+ violations: AggregatedViolation[];
85
+ duration: number;
86
+ error?: string | undefined;
87
+ }
88
+ /**
89
+ * Overall scan results
90
+ */
91
+ export interface ScanResults {
92
+ files: FileScanResult[];
93
+ patterns: AggregatedPattern[];
94
+ violations: AggregatedViolation[];
95
+ totalPatterns: number;
96
+ totalViolations: number;
97
+ totalFiles: number;
98
+ duration: number;
99
+ errors: string[];
100
+ detectorStats: {
101
+ total: number;
102
+ ran: number;
103
+ skipped: number;
104
+ };
105
+ /** Manifest with semantic locations (if generateManifest is true) */
106
+ manifest?: Manifest | undefined;
107
+ /** Worker thread stats (if useWorkerThreads is true) */
108
+ workerStats?: {
109
+ threadsUsed: number;
110
+ tasksCompleted: number;
111
+ } | undefined;
112
+ }
113
+ /**
114
+ * Scanner Service
115
+ *
116
+ * Orchestrates pattern detection across files using real detectors.
117
+ * Supports both single-threaded and multi-threaded (Piscina) modes.
118
+ */
119
+ export declare class ScannerService {
120
+ private config;
121
+ private detectors;
122
+ private initialized;
123
+ private manifestStore;
124
+ private pool;
125
+ private PiscinaClass;
126
+ constructor(config: ScannerServiceConfig);
127
+ /**
128
+ * Initialize the scanner service
129
+ */
130
+ initialize(): Promise<void>;
131
+ /**
132
+ * Warm up all worker threads by preloading detectors
133
+ * This runs warmup tasks in parallel so all workers load detectors simultaneously
134
+ */
135
+ private warmupWorkers;
136
+ /**
137
+ * Get detector count
138
+ */
139
+ getDetectorCount(): number;
140
+ /**
141
+ * Get detector counts by category
142
+ */
143
+ getDetectorCounts(): {
144
+ api: number;
145
+ auth: number;
146
+ security: number;
147
+ errors: number;
148
+ structural: number;
149
+ components: number;
150
+ styling: number;
151
+ logging: number;
152
+ testing: number;
153
+ dataAccess: number;
154
+ config: number;
155
+ types: number;
156
+ accessibility: number;
157
+ documentation: number;
158
+ performance: number;
159
+ total: number;
160
+ };
161
+ /**
162
+ * Check if worker threads are enabled and initialized
163
+ */
164
+ isUsingWorkerThreads(): boolean;
165
+ /**
166
+ * Get worker thread count
167
+ */
168
+ getWorkerThreadCount(): number;
169
+ /**
170
+ * Scan files for patterns
171
+ */
172
+ scanFiles(files: string[], projectContext: ProjectContext): Promise<ScanResults>;
173
+ /**
174
+ * Scan files using worker threads (parallel)
175
+ */
176
+ private scanFilesWithWorkers;
177
+ /**
178
+ * Aggregate results from worker threads
179
+ */
180
+ private aggregateWorkerResults;
181
+ /**
182
+ * Add pattern match to manifest
183
+ */
184
+ private addToManifest;
185
+ /**
186
+ * Scan files single-threaded (fallback)
187
+ */
188
+ private scanFilesSingleThreaded;
189
+ /**
190
+ * Create a semantic location from a basic location
191
+ */
192
+ private createSemanticLocation;
193
+ /**
194
+ * Extract semantic information from a line of code
195
+ */
196
+ private extractSemanticInfo;
197
+ /**
198
+ * Get the manifest store
199
+ */
200
+ getManifestStore(): ManifestStore | null;
201
+ /**
202
+ * Destroy the worker pool
203
+ */
204
+ destroy(): Promise<void>;
205
+ }
206
+ /**
207
+ * Create a scanner service
208
+ */
209
+ export declare function createScannerService(config: ScannerServiceConfig): ScannerService;
210
+ //# sourceMappingURL=scanner-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scanner-service.d.ts","sourceRoot":"","sources":["../../src/services/scanner-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scanner-service.d.ts","sourceRoot":"","sources":["../../src/services/scanner-service.ts"],"names":[],"mappings":"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"}