baseguard 1.0.2 → 1.0.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.
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 +628 -613
  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 +44 -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 +2 -1
  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 +2 -0
  67. package/dist/core/startup-optimizer.d.ts.map +1 -1
  68. package/dist/core/startup-optimizer.js +19 -12
  69. package/dist/core/startup-optimizer.js.map +1 -1
  70. package/dist/core/system-error-handler.d.ts.map +1 -1
  71. package/dist/core/system-error-handler.js +18 -11
  72. package/dist/core/system-error-handler.js.map +1 -1
  73. package/dist/git/automation-engine.d.ts.map +1 -1
  74. package/dist/git/automation-engine.js +5 -4
  75. package/dist/git/automation-engine.js.map +1 -1
  76. package/dist/git/github-manager.d.ts.map +1 -1
  77. package/dist/git/github-manager.js.map +1 -1
  78. package/dist/git/hook-manager.js +5 -5
  79. package/dist/git/hook-manager.js.map +1 -1
  80. package/dist/parsers/parser-manager.d.ts.map +1 -1
  81. package/dist/parsers/parser-manager.js +1 -1
  82. package/dist/parsers/parser-manager.js.map +1 -1
  83. package/dist/parsers/svelte-parser.js +1 -1
  84. package/dist/parsers/svelte-parser.js.map +1 -1
  85. package/dist/parsers/vanilla-parser.d.ts.map +1 -1
  86. package/dist/parsers/vanilla-parser.js.map +1 -1
  87. package/dist/parsers/vue-parser.d.ts.map +1 -1
  88. package/dist/parsers/vue-parser.js.map +1 -1
  89. package/dist/ui/components.d.ts +1 -1
  90. package/dist/ui/components.d.ts.map +1 -1
  91. package/dist/ui/components.js +11 -11
  92. package/dist/ui/components.js.map +1 -1
  93. package/dist/ui/terminal-header.js +14 -14
  94. package/package.json +105 -105
  95. package/src/ai/__tests__/gemini-analyzer.test.ts +180 -180
  96. package/src/ai/agentkit-orchestrator.ts +533 -533
  97. package/src/ai/fix-manager.ts +362 -362
  98. package/src/ai/gemini-analyzer.ts +665 -671
  99. package/src/ai/gemini-code-fixer.ts +539 -540
  100. package/src/ai/index.ts +3 -3
  101. package/src/ai/jules-implementer.ts +504 -460
  102. package/src/ai/unified-code-fixer.ts +347 -347
  103. package/src/commands/automation.ts +343 -343
  104. package/src/commands/check.ts +298 -299
  105. package/src/commands/config.ts +584 -583
  106. package/src/commands/fix.ts +264 -238
  107. package/src/commands/index.ts +6 -6
  108. package/src/commands/init.ts +155 -155
  109. package/src/commands/status.ts +306 -306
  110. package/src/core/api-key-manager.ts +298 -298
  111. package/src/core/baseguard.ts +757 -756
  112. package/src/core/baseline-checker.ts +564 -563
  113. package/src/core/cache-manager.ts +271 -271
  114. package/src/core/configuration-recovery.ts +672 -673
  115. package/src/core/configuration.ts +595 -595
  116. package/src/core/debug-logger.ts +590 -590
  117. package/src/core/directory-filter.ts +420 -420
  118. package/src/core/error-handler.ts +518 -517
  119. package/src/core/file-processor.ts +337 -337
  120. package/src/core/gitignore-manager.ts +168 -168
  121. package/src/core/graceful-degradation-manager.ts +596 -596
  122. package/src/core/index.ts +16 -16
  123. package/src/core/lazy-loader.ts +317 -307
  124. package/src/core/memory-manager.ts +290 -295
  125. package/src/core/parser-worker.ts +33 -0
  126. package/src/core/startup-optimizer.ts +246 -243
  127. package/src/core/system-error-handler.ts +755 -750
  128. package/src/git/automation-engine.ts +361 -361
  129. package/src/git/github-manager.ts +190 -192
  130. package/src/git/hook-manager.ts +210 -210
  131. package/src/git/index.ts +3 -3
  132. package/src/index.ts +7 -7
  133. package/src/parsers/feature-validator.ts +558 -558
  134. package/src/parsers/index.ts +7 -7
  135. package/src/parsers/parser-manager.ts +418 -419
  136. package/src/parsers/parser.ts +25 -25
  137. package/src/parsers/react-parser-optimized.ts +160 -160
  138. package/src/parsers/react-parser.ts +358 -358
  139. package/src/parsers/svelte-parser.ts +510 -510
  140. package/src/parsers/vanilla-parser.ts +685 -686
  141. package/src/parsers/vue-parser.ts +476 -478
  142. package/src/types/index.ts +95 -95
  143. package/src/ui/components.ts +567 -567
  144. package/src/ui/help.ts +192 -192
  145. package/src/ui/index.ts +3 -3
  146. package/src/ui/prompts.ts +680 -680
  147. package/src/ui/terminal-header.ts +58 -58
  148. package/test-build.js +40 -40
  149. package/test-config-commands.js +55 -55
  150. package/test-header-simple.js +32 -32
  151. package/test-terminal-header.js +11 -11
  152. package/test-ui.js +28 -28
  153. package/tests/e2e/baseguard.e2e.test.ts +515 -515
  154. package/tests/e2e/cross-platform.e2e.test.ts +419 -419
  155. package/tests/e2e/git-integration.e2e.test.ts +486 -486
  156. package/tests/fixtures/react-project/package.json +13 -13
  157. package/tests/fixtures/react-project/src/App.css +75 -75
  158. package/tests/fixtures/react-project/src/App.tsx +76 -76
  159. package/tests/fixtures/svelte-project/package.json +10 -10
  160. package/tests/fixtures/svelte-project/src/App.svelte +368 -368
  161. package/tests/fixtures/vanilla-project/index.html +75 -75
  162. package/tests/fixtures/vanilla-project/script.js +330 -330
  163. package/tests/fixtures/vanilla-project/styles.css +358 -358
  164. package/tests/fixtures/vue-project/package.json +11 -11
  165. package/tests/fixtures/vue-project/src/App.vue +215 -215
  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
+ }