baseguard 1.0.3 → 1.0.5

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 (169) hide show
  1. package/.baseguardrc.example.json +63 -63
  2. package/.eslintrc.json +24 -24
  3. package/.prettierrc +7 -7
  4. package/CHANGELOG.md +195 -195
  5. package/DEPLOYMENT.md +624 -624
  6. package/DEPLOYMENT_CHECKLIST.md +239 -239
  7. package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -202
  8. package/QUICK_START.md +134 -134
  9. package/README.md +488 -488
  10. package/RELEASE_NOTES_v1.0.2.md +434 -434
  11. package/bin/base.js +627 -627
  12. package/dist/ai/fix-manager.d.ts.map +1 -1
  13. package/dist/ai/fix-manager.js +1 -1
  14. package/dist/ai/fix-manager.js.map +1 -1
  15. package/dist/ai/gemini-analyzer.d.ts.map +1 -1
  16. package/dist/ai/gemini-analyzer.js +29 -35
  17. package/dist/ai/gemini-analyzer.js.map +1 -1
  18. package/dist/ai/gemini-code-fixer.d.ts.map +1 -1
  19. package/dist/ai/gemini-code-fixer.js +58 -58
  20. package/dist/ai/gemini-code-fixer.js.map +1 -1
  21. package/dist/ai/jules-implementer.d.ts +3 -0
  22. package/dist/ai/jules-implementer.d.ts.map +1 -1
  23. package/dist/ai/jules-implementer.js +63 -32
  24. package/dist/ai/jules-implementer.js.map +1 -1
  25. package/dist/ai/unified-code-fixer.js.map +1 -1
  26. package/dist/commands/check.d.ts.map +1 -1
  27. package/dist/commands/check.js +1 -1
  28. package/dist/commands/check.js.map +1 -1
  29. package/dist/commands/config.js +2 -1
  30. package/dist/commands/config.js.map +1 -1
  31. package/dist/commands/fix.d.ts.map +1 -1
  32. package/dist/commands/fix.js +48 -15
  33. package/dist/commands/fix.js.map +1 -1
  34. package/dist/core/api-key-manager.js +2 -2
  35. package/dist/core/api-key-manager.js.map +1 -1
  36. package/dist/core/baseguard.d.ts +1 -0
  37. package/dist/core/baseguard.d.ts.map +1 -1
  38. package/dist/core/baseguard.js +13 -10
  39. package/dist/core/baseguard.js.map +1 -1
  40. package/dist/core/baseline-checker.d.ts.map +1 -1
  41. package/dist/core/baseline-checker.js +8 -5
  42. package/dist/core/baseline-checker.js.map +1 -1
  43. package/dist/core/configuration-recovery.d.ts.map +1 -1
  44. package/dist/core/configuration-recovery.js +1 -1
  45. package/dist/core/configuration-recovery.js.map +1 -1
  46. package/dist/core/debug-logger.d.ts.map +1 -1
  47. package/dist/core/debug-logger.js +1 -1
  48. package/dist/core/debug-logger.js.map +1 -1
  49. package/dist/core/error-handler.d.ts.map +1 -1
  50. package/dist/core/error-handler.js +2 -1
  51. package/dist/core/error-handler.js.map +1 -1
  52. package/dist/core/gitignore-manager.js +5 -5
  53. package/dist/core/graceful-degradation-manager.d.ts.map +1 -1
  54. package/dist/core/graceful-degradation-manager.js +16 -16
  55. package/dist/core/graceful-degradation-manager.js.map +1 -1
  56. package/dist/core/lazy-loader.d.ts.map +1 -1
  57. package/dist/core/lazy-loader.js +9 -2
  58. package/dist/core/lazy-loader.js.map +1 -1
  59. package/dist/core/memory-manager.d.ts +0 -3
  60. package/dist/core/memory-manager.d.ts.map +1 -1
  61. package/dist/core/memory-manager.js.map +1 -1
  62. package/dist/core/parser-worker.d.ts +2 -0
  63. package/dist/core/parser-worker.d.ts.map +1 -0
  64. package/dist/core/parser-worker.js +19 -0
  65. package/dist/core/parser-worker.js.map +1 -0
  66. package/dist/core/startup-optimizer.d.ts.map +1 -1
  67. package/dist/core/startup-optimizer.js +4 -8
  68. package/dist/core/startup-optimizer.js.map +1 -1
  69. package/dist/core/system-error-handler.d.ts.map +1 -1
  70. package/dist/core/system-error-handler.js.map +1 -1
  71. package/dist/git/automation-engine.d.ts.map +1 -1
  72. package/dist/git/automation-engine.js +5 -4
  73. package/dist/git/automation-engine.js.map +1 -1
  74. package/dist/git/github-manager.d.ts.map +1 -1
  75. package/dist/git/github-manager.js.map +1 -1
  76. package/dist/git/hook-manager.js +5 -5
  77. package/dist/git/hook-manager.js.map +1 -1
  78. package/dist/parsers/parser-manager.d.ts.map +1 -1
  79. package/dist/parsers/parser-manager.js +1 -1
  80. package/dist/parsers/parser-manager.js.map +1 -1
  81. package/dist/parsers/svelte-parser.js +1 -1
  82. package/dist/parsers/svelte-parser.js.map +1 -1
  83. package/dist/parsers/vanilla-parser.d.ts.map +1 -1
  84. package/dist/parsers/vanilla-parser.js.map +1 -1
  85. package/dist/parsers/vue-parser.d.ts.map +1 -1
  86. package/dist/parsers/vue-parser.js.map +1 -1
  87. package/dist/ui/components.d.ts +1 -1
  88. package/dist/ui/components.d.ts.map +1 -1
  89. package/dist/ui/components.js +11 -11
  90. package/dist/ui/components.js.map +1 -1
  91. package/dist/ui/terminal-header.js +14 -14
  92. package/package.json +105 -105
  93. package/src/ai/__tests__/gemini-analyzer.test.ts +180 -180
  94. package/src/ai/agentkit-orchestrator.ts +533 -533
  95. package/src/ai/fix-manager.ts +362 -362
  96. package/src/ai/gemini-analyzer.ts +665 -671
  97. package/src/ai/gemini-code-fixer.ts +539 -540
  98. package/src/ai/index.ts +3 -3
  99. package/src/ai/jules-implementer.ts +504 -460
  100. package/src/ai/unified-code-fixer.ts +347 -347
  101. package/src/commands/automation.ts +343 -343
  102. package/src/commands/check.ts +298 -299
  103. package/src/commands/config.ts +584 -583
  104. package/src/commands/fix.ts +269 -238
  105. package/src/commands/index.ts +6 -6
  106. package/src/commands/init.ts +155 -155
  107. package/src/commands/status.ts +306 -306
  108. package/src/core/api-key-manager.ts +298 -298
  109. package/src/core/baseguard.ts +757 -756
  110. package/src/core/baseline-checker.ts +566 -563
  111. package/src/core/cache-manager.ts +271 -271
  112. package/src/core/configuration-recovery.ts +672 -673
  113. package/src/core/configuration.ts +595 -595
  114. package/src/core/debug-logger.ts +590 -590
  115. package/src/core/directory-filter.ts +420 -420
  116. package/src/core/error-handler.ts +518 -517
  117. package/src/core/file-processor.ts +337 -337
  118. package/src/core/gitignore-manager.ts +168 -168
  119. package/src/core/graceful-degradation-manager.ts +596 -596
  120. package/src/core/index.ts +16 -16
  121. package/src/core/lazy-loader.ts +317 -307
  122. package/src/core/memory-manager.ts +290 -295
  123. package/src/core/parser-worker.ts +33 -0
  124. package/src/core/startup-optimizer.ts +246 -255
  125. package/src/core/system-error-handler.ts +755 -756
  126. package/src/git/automation-engine.ts +361 -361
  127. package/src/git/github-manager.ts +190 -192
  128. package/src/git/hook-manager.ts +210 -210
  129. package/src/git/index.ts +3 -3
  130. package/src/index.ts +7 -7
  131. package/src/parsers/feature-validator.ts +558 -558
  132. package/src/parsers/index.ts +7 -7
  133. package/src/parsers/parser-manager.ts +418 -419
  134. package/src/parsers/parser.ts +25 -25
  135. package/src/parsers/react-parser-optimized.ts +160 -160
  136. package/src/parsers/react-parser.ts +358 -358
  137. package/src/parsers/svelte-parser.ts +510 -510
  138. package/src/parsers/vanilla-parser.ts +685 -686
  139. package/src/parsers/vue-parser.ts +476 -478
  140. package/src/types/index.ts +95 -95
  141. package/src/ui/components.ts +567 -567
  142. package/src/ui/help.ts +192 -192
  143. package/src/ui/index.ts +3 -3
  144. package/src/ui/prompts.ts +680 -680
  145. package/src/ui/terminal-header.ts +58 -58
  146. package/test-build.js +40 -40
  147. package/test-config-commands.js +55 -55
  148. package/test-header-simple.js +32 -32
  149. package/test-terminal-header.js +11 -11
  150. package/test-ui.js +28 -28
  151. package/tests/e2e/baseguard.e2e.test.ts +515 -515
  152. package/tests/e2e/cross-platform.e2e.test.ts +419 -419
  153. package/tests/e2e/git-integration.e2e.test.ts +486 -486
  154. package/tests/fixtures/react-project/package.json +13 -13
  155. package/tests/fixtures/react-project/src/App.css +75 -75
  156. package/tests/fixtures/react-project/src/App.tsx +76 -76
  157. package/tests/fixtures/svelte-project/package.json +10 -10
  158. package/tests/fixtures/svelte-project/src/App.svelte +368 -368
  159. package/tests/fixtures/vanilla-project/index.html +75 -75
  160. package/tests/fixtures/vanilla-project/script.js +330 -330
  161. package/tests/fixtures/vanilla-project/styles.css +358 -358
  162. package/tests/fixtures/vue-project/package.json +11 -11
  163. package/tests/fixtures/vue-project/src/App.vue +215 -215
  164. package/tmp-smoke/.baseguard/backups/config-2026-02-19T12-04-11-067Z-auto.json +30 -0
  165. package/tmp-smoke/src/bad.css +3 -0
  166. package/tsconfig.json +34 -34
  167. package/vitest.config.ts +11 -11
  168. package/dist/terminal-header.d.ts +0 -12
  169. package/dist/terminal-header.js +0 -45
@@ -1,295 +1,290 @@
1
- import { createReadStream } from 'fs';
2
- import { createInterface } from 'readline';
3
-
4
- // Use Node.js built-in gc type
5
- declare global {
6
- var gc: NodeJS.GCFunction | undefined;
7
- }
8
-
9
- /**
10
- * Memory-efficient file processing and streaming
11
- */
12
- export class MemoryManager {
13
- private static readonly MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
14
- private static readonly CHUNK_SIZE = 64 * 1024; // 64KB chunks
15
- private static readonly GC_THRESHOLD = 100 * 1024 * 1024; // 100MB
16
-
17
- /**
18
- * Check if file should be processed in streaming mode
19
- */
20
- static shouldStream(fileSize: number): boolean {
21
- return fileSize > this.MAX_FILE_SIZE;
22
- }
23
-
24
- /**
25
- * Read large file in chunks using streaming
26
- */
27
- static async readFileStreaming(
28
- filePath: string,
29
- processor: (chunk: string, lineNumber: number) => Promise<void>
30
- ): Promise<void> {
31
- return new Promise((resolve, reject) => {
32
- const fileStream = createReadStream(filePath, {
33
- encoding: 'utf8',
34
- highWaterMark: this.CHUNK_SIZE
35
- });
36
-
37
- const rl = createInterface({
38
- input: fileStream,
39
- crlfDelay: Infinity
40
- });
41
-
42
- let lineNumber = 0;
43
- let currentChunk = '';
44
- let chunkLineCount = 0;
45
-
46
- rl.on('line', async (line) => {
47
- lineNumber++;
48
- currentChunk += line + '\n';
49
- chunkLineCount++;
50
-
51
- // Process in chunks to avoid memory buildup
52
- if (chunkLineCount >= 1000) {
53
- try {
54
- await processor(currentChunk, lineNumber - chunkLineCount + 1);
55
- currentChunk = '';
56
- chunkLineCount = 0;
57
-
58
- // Force garbage collection if available
59
- this.tryGarbageCollect();
60
- } catch (error) {
61
- rl.close();
62
- reject(error);
63
- return;
64
- }
65
- }
66
- });
67
-
68
- rl.on('close', async () => {
69
- try {
70
- // Process remaining chunk
71
- if (currentChunk.trim()) {
72
- await processor(currentChunk, lineNumber - chunkLineCount + 1);
73
- }
74
- resolve();
75
- } catch (error) {
76
- reject(error);
77
- }
78
- });
79
-
80
- rl.on('error', reject);
81
- fileStream.on('error', reject);
82
- });
83
- }
84
-
85
- /**
86
- * Process array in memory-efficient batches
87
- */
88
- static async processBatches<T, R>(
89
- items: T[],
90
- processor: (batch: T[]) => Promise<R[]>,
91
- batchSize: number = 100
92
- ): Promise<R[]> {
93
- const results: R[] = [];
94
-
95
- for (let i = 0; i < items.length; i += batchSize) {
96
- const batch = items.slice(i, i + batchSize);
97
-
98
- try {
99
- const batchResults = await processor(batch);
100
- results.push(...batchResults);
101
-
102
- // Force garbage collection between batches
103
- this.tryGarbageCollect();
104
-
105
- // Small delay to prevent overwhelming the system
106
- if (i + batchSize < items.length) {
107
- await this.sleep(1);
108
- }
109
- } catch (error) {
110
- console.warn(`Error processing batch ${i}-${i + batchSize}: ${error}`);
111
- }
112
- }
113
-
114
- return results;
115
- }
116
-
117
- /**
118
- * Monitor memory usage and warn if high
119
- */
120
- static checkMemoryUsage(): {
121
- usage: NodeJS.MemoryUsage;
122
- warning?: string;
123
- } {
124
- const usage = process.memoryUsage();
125
- let warning: string | undefined;
126
-
127
- // Check if memory usage is high (over 100MB heap used)
128
- if (usage.heapUsed > this.GC_THRESHOLD) {
129
- warning = `High memory usage detected: ${Math.round(usage.heapUsed / 1024 / 1024)}MB heap used`;
130
- }
131
-
132
- return { usage, warning };
133
- }
134
-
135
- /**
136
- * Try to trigger garbage collection if available
137
- */
138
- static tryGarbageCollect(): void {
139
- if (global.gc) {
140
- try {
141
- global.gc();
142
- } catch (error) {
143
- // Ignore GC errors
144
- }
145
- }
146
- }
147
-
148
- /**
149
- * Sleep utility for batch processing
150
- */
151
- static sleep(ms: number): Promise<void> {
152
- return new Promise(resolve => setTimeout(resolve, ms));
153
- }
154
-
155
- /**
156
- * Create memory-efficient data structure for violations
157
- */
158
- static createViolationTracker(): ViolationTracker {
159
- return new ViolationTracker();
160
- }
161
-
162
- /**
163
- * Optimize object for memory usage by removing undefined properties
164
- */
165
- static optimizeObject<T extends Record<string, any>>(obj: T): T {
166
- const optimized = {} as T;
167
-
168
- for (const [key, value] of Object.entries(obj)) {
169
- if (value !== undefined && value !== null) {
170
- optimized[key as keyof T] = value;
171
- }
172
- }
173
-
174
- return optimized;
175
- }
176
-
177
- /**
178
- * Get memory usage statistics
179
- */
180
- static getMemoryStats(): {
181
- heapUsed: string;
182
- heapTotal: string;
183
- external: string;
184
- rss: string;
185
- } {
186
- const usage = process.memoryUsage();
187
-
188
- return {
189
- heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
190
- heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
191
- external: `${Math.round(usage.external / 1024 / 1024)}MB`,
192
- rss: `${Math.round(usage.rss / 1024 / 1024)}MB`
193
- };
194
- }
195
- }
196
-
197
- /**
198
- * Memory-efficient violation tracking
199
- */
200
- class ViolationTracker {
201
- private violations = new Map<string, any>();
202
- private fileIndex = new Map<string, number>();
203
- private nextFileId = 0;
204
-
205
- /**
206
- * Add violation with memory optimization
207
- */
208
- addViolation(violation: any): void {
209
- // Optimize file path storage using indices
210
- let fileId = this.fileIndex.get(violation.file);
211
- if (fileId === undefined) {
212
- fileId = this.nextFileId++;
213
- this.fileIndex.set(violation.file, fileId);
214
- }
215
-
216
- // Create optimized violation object
217
- const optimized = {
218
- f: violation.feature,
219
- fid: violation.featureId,
220
- fi: fileId, // file index instead of full path
221
- l: violation.line,
222
- c: violation.column,
223
- ctx: violation.context?.substring(0, 100), // Limit context length
224
- b: violation.browser,
225
- r: violation.required,
226
- a: violation.actual,
227
- bs: violation.baselineStatus,
228
- rs: violation.reason?.substring(0, 200) // Limit reason length
229
- };
230
-
231
- const key = `${fileId}-${violation.line}-${violation.feature}`;
232
- this.violations.set(key, optimized);
233
- }
234
-
235
- /**
236
- * Get all violations with full data
237
- */
238
- getViolations(): any[] {
239
- const result: any[] = [];
240
- const fileIdToPath = new Map<number, string>();
241
-
242
- // Create reverse mapping
243
- for (const [path, id] of this.fileIndex) {
244
- fileIdToPath.set(id, path);
245
- }
246
-
247
- for (const optimized of this.violations.values()) {
248
- result.push({
249
- feature: optimized.f,
250
- featureId: optimized.fid,
251
- file: fileIdToPath.get(optimized.fi) || 'unknown',
252
- line: optimized.l,
253
- column: optimized.c,
254
- context: optimized.ctx,
255
- browser: optimized.b,
256
- required: optimized.r,
257
- actual: optimized.a,
258
- baselineStatus: optimized.bs,
259
- reason: optimized.rs
260
- });
261
- }
262
-
263
- return result;
264
- }
265
-
266
- /**
267
- * Get memory usage statistics
268
- */
269
- getStats(): {
270
- violationCount: number;
271
- fileCount: number;
272
- memoryEstimate: string;
273
- } {
274
- const violationCount = this.violations.size;
275
- const fileCount = this.fileIndex.size;
276
-
277
- // Rough memory estimate (each violation ~200 bytes)
278
- const memoryEstimate = `${Math.round(violationCount * 200 / 1024)}KB`;
279
-
280
- return {
281
- violationCount,
282
- fileCount,
283
- memoryEstimate
284
- };
285
- }
286
-
287
- /**
288
- * Clear all data
289
- */
290
- clear(): void {
291
- this.violations.clear();
292
- this.fileIndex.clear();
293
- this.nextFileId = 0;
294
- }
295
- }
1
+ import { createReadStream } from 'fs';
2
+ import { createInterface } from 'readline';
3
+
4
+ /**
5
+ * Memory-efficient file processing and streaming
6
+ */
7
+ export class MemoryManager {
8
+ private static readonly MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
9
+ private static readonly CHUNK_SIZE = 64 * 1024; // 64KB chunks
10
+ private static readonly GC_THRESHOLD = 100 * 1024 * 1024; // 100MB
11
+
12
+ /**
13
+ * Check if file should be processed in streaming mode
14
+ */
15
+ static shouldStream(fileSize: number): boolean {
16
+ return fileSize > this.MAX_FILE_SIZE;
17
+ }
18
+
19
+ /**
20
+ * Read large file in chunks using streaming
21
+ */
22
+ static async readFileStreaming(
23
+ filePath: string,
24
+ processor: (chunk: string, lineNumber: number) => Promise<void>
25
+ ): Promise<void> {
26
+ return new Promise((resolve, reject) => {
27
+ const fileStream = createReadStream(filePath, {
28
+ encoding: 'utf8',
29
+ highWaterMark: this.CHUNK_SIZE
30
+ });
31
+
32
+ const rl = createInterface({
33
+ input: fileStream,
34
+ crlfDelay: Infinity
35
+ });
36
+
37
+ let lineNumber = 0;
38
+ let currentChunk = '';
39
+ let chunkLineCount = 0;
40
+
41
+ rl.on('line', async (line) => {
42
+ lineNumber++;
43
+ currentChunk += line + '\n';
44
+ chunkLineCount++;
45
+
46
+ // Process in chunks to avoid memory buildup
47
+ if (chunkLineCount >= 1000) {
48
+ try {
49
+ await processor(currentChunk, lineNumber - chunkLineCount + 1);
50
+ currentChunk = '';
51
+ chunkLineCount = 0;
52
+
53
+ // Force garbage collection if available
54
+ this.tryGarbageCollect();
55
+ } catch (error) {
56
+ rl.close();
57
+ reject(error);
58
+ return;
59
+ }
60
+ }
61
+ });
62
+
63
+ rl.on('close', async () => {
64
+ try {
65
+ // Process remaining chunk
66
+ if (currentChunk.trim()) {
67
+ await processor(currentChunk, lineNumber - chunkLineCount + 1);
68
+ }
69
+ resolve();
70
+ } catch (error) {
71
+ reject(error);
72
+ }
73
+ });
74
+
75
+ rl.on('error', reject);
76
+ fileStream.on('error', reject);
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Process array in memory-efficient batches
82
+ */
83
+ static async processBatches<T, R>(
84
+ items: T[],
85
+ processor: (batch: T[]) => Promise<R[]>,
86
+ batchSize: number = 100
87
+ ): Promise<R[]> {
88
+ const results: R[] = [];
89
+
90
+ for (let i = 0; i < items.length; i += batchSize) {
91
+ const batch = items.slice(i, i + batchSize);
92
+
93
+ try {
94
+ const batchResults = await processor(batch);
95
+ results.push(...batchResults);
96
+
97
+ // Force garbage collection between batches
98
+ this.tryGarbageCollect();
99
+
100
+ // Small delay to prevent overwhelming the system
101
+ if (i + batchSize < items.length) {
102
+ await this.sleep(1);
103
+ }
104
+ } catch (error) {
105
+ console.warn(`Error processing batch ${i}-${i + batchSize}: ${error}`);
106
+ }
107
+ }
108
+
109
+ return results;
110
+ }
111
+
112
+ /**
113
+ * Monitor memory usage and warn if high
114
+ */
115
+ static checkMemoryUsage(): {
116
+ usage: NodeJS.MemoryUsage;
117
+ warning?: string;
118
+ } {
119
+ const usage = process.memoryUsage();
120
+ let warning: string | undefined;
121
+
122
+ // Check if memory usage is high (over 100MB heap used)
123
+ if (usage.heapUsed > this.GC_THRESHOLD) {
124
+ warning = `High memory usage detected: ${Math.round(usage.heapUsed / 1024 / 1024)}MB heap used`;
125
+ }
126
+
127
+ return { usage, warning };
128
+ }
129
+
130
+ /**
131
+ * Try to trigger garbage collection if available
132
+ */
133
+ static tryGarbageCollect(): void {
134
+ if (global.gc) {
135
+ try {
136
+ global.gc();
137
+ } catch (error) {
138
+ // Ignore GC errors
139
+ }
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Sleep utility for batch processing
145
+ */
146
+ static sleep(ms: number): Promise<void> {
147
+ return new Promise(resolve => setTimeout(resolve, ms));
148
+ }
149
+
150
+ /**
151
+ * Create memory-efficient data structure for violations
152
+ */
153
+ static createViolationTracker(): ViolationTracker {
154
+ return new ViolationTracker();
155
+ }
156
+
157
+ /**
158
+ * Optimize object for memory usage by removing undefined properties
159
+ */
160
+ static optimizeObject<T extends Record<string, any>>(obj: T): T {
161
+ const optimized = {} as T;
162
+
163
+ for (const [key, value] of Object.entries(obj)) {
164
+ if (value !== undefined && value !== null) {
165
+ optimized[key as keyof T] = value;
166
+ }
167
+ }
168
+
169
+ return optimized;
170
+ }
171
+
172
+ /**
173
+ * Get memory usage statistics
174
+ */
175
+ static getMemoryStats(): {
176
+ heapUsed: string;
177
+ heapTotal: string;
178
+ external: string;
179
+ rss: string;
180
+ } {
181
+ const usage = process.memoryUsage();
182
+
183
+ return {
184
+ heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
185
+ heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
186
+ external: `${Math.round(usage.external / 1024 / 1024)}MB`,
187
+ rss: `${Math.round(usage.rss / 1024 / 1024)}MB`
188
+ };
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Memory-efficient violation tracking
194
+ */
195
+ class ViolationTracker {
196
+ private violations = new Map<string, any>();
197
+ private fileIndex = new Map<string, number>();
198
+ private nextFileId = 0;
199
+
200
+ /**
201
+ * Add violation with memory optimization
202
+ */
203
+ addViolation(violation: any): void {
204
+ // Optimize file path storage using indices
205
+ let fileId = this.fileIndex.get(violation.file);
206
+ if (fileId === undefined) {
207
+ fileId = this.nextFileId++;
208
+ this.fileIndex.set(violation.file, fileId);
209
+ }
210
+
211
+ // Create optimized violation object
212
+ const optimized = {
213
+ f: violation.feature,
214
+ fid: violation.featureId,
215
+ fi: fileId, // file index instead of full path
216
+ l: violation.line,
217
+ c: violation.column,
218
+ ctx: violation.context?.substring(0, 100), // Limit context length
219
+ b: violation.browser,
220
+ r: violation.required,
221
+ a: violation.actual,
222
+ bs: violation.baselineStatus,
223
+ rs: violation.reason?.substring(0, 200) // Limit reason length
224
+ };
225
+
226
+ const key = `${fileId}-${violation.line}-${violation.feature}`;
227
+ this.violations.set(key, optimized);
228
+ }
229
+
230
+ /**
231
+ * Get all violations with full data
232
+ */
233
+ getViolations(): any[] {
234
+ const result: any[] = [];
235
+ const fileIdToPath = new Map<number, string>();
236
+
237
+ // Create reverse mapping
238
+ for (const [path, id] of this.fileIndex) {
239
+ fileIdToPath.set(id, path);
240
+ }
241
+
242
+ for (const optimized of this.violations.values()) {
243
+ result.push({
244
+ feature: optimized.f,
245
+ featureId: optimized.fid,
246
+ file: fileIdToPath.get(optimized.fi) || 'unknown',
247
+ line: optimized.l,
248
+ column: optimized.c,
249
+ context: optimized.ctx,
250
+ browser: optimized.b,
251
+ required: optimized.r,
252
+ actual: optimized.a,
253
+ baselineStatus: optimized.bs,
254
+ reason: optimized.rs
255
+ });
256
+ }
257
+
258
+ return result;
259
+ }
260
+
261
+ /**
262
+ * Get memory usage statistics
263
+ */
264
+ getStats(): {
265
+ violationCount: number;
266
+ fileCount: number;
267
+ memoryEstimate: string;
268
+ } {
269
+ const violationCount = this.violations.size;
270
+ const fileCount = this.fileIndex.size;
271
+
272
+ // Rough memory estimate (each violation ~200 bytes)
273
+ const memoryEstimate = `${Math.round(violationCount * 200 / 1024)}KB`;
274
+
275
+ return {
276
+ violationCount,
277
+ fileCount,
278
+ memoryEstimate
279
+ };
280
+ }
281
+
282
+ /**
283
+ * Clear all data
284
+ */
285
+ clear(): void {
286
+ this.violations.clear();
287
+ this.fileIndex.clear();
288
+ this.nextFileId = 0;
289
+ }
290
+ }
@@ -0,0 +1,33 @@
1
+ import { parentPort } from 'worker_threads';
2
+ import { ParserManager } from '../parsers/parser-manager.js';
3
+ import type { DetectedFeature } from '../types/index.js';
4
+
5
+ interface WorkerTask {
6
+ id: string;
7
+ filePath: string;
8
+ }
9
+
10
+ interface WorkerResult {
11
+ id: string;
12
+ features: DetectedFeature[];
13
+ error?: string;
14
+ }
15
+
16
+ const parserManager = new ParserManager(1);
17
+
18
+ if (parentPort) {
19
+ parentPort.on('message', async (task: WorkerTask) => {
20
+ const result: WorkerResult = {
21
+ id: task.id,
22
+ features: []
23
+ };
24
+
25
+ try {
26
+ result.features = await parserManager.parseFile(task.filePath);
27
+ } catch (error) {
28
+ result.error = error instanceof Error ? error.message : 'Unknown parsing error';
29
+ }
30
+
31
+ parentPort?.postMessage(result);
32
+ });
33
+ }