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.
- package/.baseguardrc.example.json +63 -63
- package/.eslintrc.json +24 -24
- package/.prettierrc +7 -7
- package/CHANGELOG.md +195 -195
- package/DEPLOYMENT.md +624 -624
- package/DEPLOYMENT_CHECKLIST.md +239 -239
- package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -202
- package/QUICK_START.md +134 -134
- package/README.md +488 -488
- package/RELEASE_NOTES_v1.0.2.md +434 -434
- package/bin/base.js +628 -613
- package/dist/ai/fix-manager.d.ts.map +1 -1
- package/dist/ai/fix-manager.js +1 -1
- package/dist/ai/fix-manager.js.map +1 -1
- package/dist/ai/gemini-analyzer.d.ts.map +1 -1
- package/dist/ai/gemini-analyzer.js +29 -35
- package/dist/ai/gemini-analyzer.js.map +1 -1
- package/dist/ai/gemini-code-fixer.d.ts.map +1 -1
- package/dist/ai/gemini-code-fixer.js +58 -58
- package/dist/ai/gemini-code-fixer.js.map +1 -1
- package/dist/ai/jules-implementer.d.ts +3 -0
- package/dist/ai/jules-implementer.d.ts.map +1 -1
- package/dist/ai/jules-implementer.js +63 -32
- package/dist/ai/jules-implementer.js.map +1 -1
- package/dist/ai/unified-code-fixer.js.map +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +1 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/config.js +2 -1
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +44 -15
- package/dist/commands/fix.js.map +1 -1
- package/dist/core/api-key-manager.js +2 -2
- package/dist/core/api-key-manager.js.map +1 -1
- package/dist/core/baseguard.d.ts +1 -0
- package/dist/core/baseguard.d.ts.map +1 -1
- package/dist/core/baseguard.js +13 -10
- package/dist/core/baseguard.js.map +1 -1
- package/dist/core/baseline-checker.d.ts.map +1 -1
- package/dist/core/baseline-checker.js +2 -1
- package/dist/core/baseline-checker.js.map +1 -1
- package/dist/core/configuration-recovery.d.ts.map +1 -1
- package/dist/core/configuration-recovery.js +1 -1
- package/dist/core/configuration-recovery.js.map +1 -1
- package/dist/core/debug-logger.d.ts.map +1 -1
- package/dist/core/debug-logger.js +1 -1
- package/dist/core/debug-logger.js.map +1 -1
- package/dist/core/error-handler.d.ts.map +1 -1
- package/dist/core/error-handler.js +2 -1
- package/dist/core/error-handler.js.map +1 -1
- package/dist/core/gitignore-manager.js +5 -5
- package/dist/core/graceful-degradation-manager.d.ts.map +1 -1
- package/dist/core/graceful-degradation-manager.js +16 -16
- package/dist/core/graceful-degradation-manager.js.map +1 -1
- package/dist/core/lazy-loader.d.ts.map +1 -1
- package/dist/core/lazy-loader.js +9 -2
- package/dist/core/lazy-loader.js.map +1 -1
- package/dist/core/memory-manager.d.ts +0 -3
- package/dist/core/memory-manager.d.ts.map +1 -1
- package/dist/core/memory-manager.js.map +1 -1
- package/dist/core/parser-worker.d.ts +2 -0
- package/dist/core/parser-worker.d.ts.map +1 -0
- package/dist/core/parser-worker.js +19 -0
- package/dist/core/parser-worker.js.map +1 -0
- package/dist/core/startup-optimizer.d.ts +2 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -1
- package/dist/core/startup-optimizer.js +19 -12
- package/dist/core/startup-optimizer.js.map +1 -1
- package/dist/core/system-error-handler.d.ts.map +1 -1
- package/dist/core/system-error-handler.js +18 -11
- package/dist/core/system-error-handler.js.map +1 -1
- package/dist/git/automation-engine.d.ts.map +1 -1
- package/dist/git/automation-engine.js +5 -4
- package/dist/git/automation-engine.js.map +1 -1
- package/dist/git/github-manager.d.ts.map +1 -1
- package/dist/git/github-manager.js.map +1 -1
- package/dist/git/hook-manager.js +5 -5
- package/dist/git/hook-manager.js.map +1 -1
- package/dist/parsers/parser-manager.d.ts.map +1 -1
- package/dist/parsers/parser-manager.js +1 -1
- package/dist/parsers/parser-manager.js.map +1 -1
- package/dist/parsers/svelte-parser.js +1 -1
- package/dist/parsers/svelte-parser.js.map +1 -1
- package/dist/parsers/vanilla-parser.d.ts.map +1 -1
- package/dist/parsers/vanilla-parser.js.map +1 -1
- package/dist/parsers/vue-parser.d.ts.map +1 -1
- package/dist/parsers/vue-parser.js.map +1 -1
- package/dist/ui/components.d.ts +1 -1
- package/dist/ui/components.d.ts.map +1 -1
- package/dist/ui/components.js +11 -11
- package/dist/ui/components.js.map +1 -1
- package/dist/ui/terminal-header.js +14 -14
- package/package.json +105 -105
- package/src/ai/__tests__/gemini-analyzer.test.ts +180 -180
- package/src/ai/agentkit-orchestrator.ts +533 -533
- package/src/ai/fix-manager.ts +362 -362
- package/src/ai/gemini-analyzer.ts +665 -671
- package/src/ai/gemini-code-fixer.ts +539 -540
- package/src/ai/index.ts +3 -3
- package/src/ai/jules-implementer.ts +504 -460
- package/src/ai/unified-code-fixer.ts +347 -347
- package/src/commands/automation.ts +343 -343
- package/src/commands/check.ts +298 -299
- package/src/commands/config.ts +584 -583
- package/src/commands/fix.ts +264 -238
- package/src/commands/index.ts +6 -6
- package/src/commands/init.ts +155 -155
- package/src/commands/status.ts +306 -306
- package/src/core/api-key-manager.ts +298 -298
- package/src/core/baseguard.ts +757 -756
- package/src/core/baseline-checker.ts +564 -563
- package/src/core/cache-manager.ts +271 -271
- package/src/core/configuration-recovery.ts +672 -673
- package/src/core/configuration.ts +595 -595
- package/src/core/debug-logger.ts +590 -590
- package/src/core/directory-filter.ts +420 -420
- package/src/core/error-handler.ts +518 -517
- package/src/core/file-processor.ts +337 -337
- package/src/core/gitignore-manager.ts +168 -168
- package/src/core/graceful-degradation-manager.ts +596 -596
- package/src/core/index.ts +16 -16
- package/src/core/lazy-loader.ts +317 -307
- package/src/core/memory-manager.ts +290 -295
- package/src/core/parser-worker.ts +33 -0
- package/src/core/startup-optimizer.ts +246 -243
- package/src/core/system-error-handler.ts +755 -750
- package/src/git/automation-engine.ts +361 -361
- package/src/git/github-manager.ts +190 -192
- package/src/git/hook-manager.ts +210 -210
- package/src/git/index.ts +3 -3
- package/src/index.ts +7 -7
- package/src/parsers/feature-validator.ts +558 -558
- package/src/parsers/index.ts +7 -7
- package/src/parsers/parser-manager.ts +418 -419
- package/src/parsers/parser.ts +25 -25
- package/src/parsers/react-parser-optimized.ts +160 -160
- package/src/parsers/react-parser.ts +358 -358
- package/src/parsers/svelte-parser.ts +510 -510
- package/src/parsers/vanilla-parser.ts +685 -686
- package/src/parsers/vue-parser.ts +476 -478
- package/src/types/index.ts +95 -95
- package/src/ui/components.ts +567 -567
- package/src/ui/help.ts +192 -192
- package/src/ui/index.ts +3 -3
- package/src/ui/prompts.ts +680 -680
- package/src/ui/terminal-header.ts +58 -58
- package/test-build.js +40 -40
- package/test-config-commands.js +55 -55
- package/test-header-simple.js +32 -32
- package/test-terminal-header.js +11 -11
- package/test-ui.js +28 -28
- package/tests/e2e/baseguard.e2e.test.ts +515 -515
- package/tests/e2e/cross-platform.e2e.test.ts +419 -419
- package/tests/e2e/git-integration.e2e.test.ts +486 -486
- package/tests/fixtures/react-project/package.json +13 -13
- package/tests/fixtures/react-project/src/App.css +75 -75
- package/tests/fixtures/react-project/src/App.tsx +76 -76
- package/tests/fixtures/svelte-project/package.json +10 -10
- package/tests/fixtures/svelte-project/src/App.svelte +368 -368
- package/tests/fixtures/vanilla-project/index.html +75 -75
- package/tests/fixtures/vanilla-project/script.js +330 -330
- package/tests/fixtures/vanilla-project/styles.css +358 -358
- package/tests/fixtures/vue-project/package.json +11 -11
- package/tests/fixtures/vue-project/src/App.vue +215 -215
- package/tsconfig.json +34 -34
- package/vitest.config.ts +11 -11
- package/dist/terminal-header.d.ts +0 -12
- package/dist/terminal-header.js +0 -45
|
@@ -1,540 +1,539 @@
|
|
|
1
|
-
import type { Violation, Analysis, Fix } from '../types/index.js';
|
|
2
|
-
import { promises as fs } from 'fs';
|
|
3
|
-
import { ErrorHandler, APIError, ErrorType } from '../core/error-handler.js';
|
|
4
|
-
import { logger } from '../core/debug-logger.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
this.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
'
|
|
64
|
-
'
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
'
|
|
82
|
-
'
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
'
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
- **
|
|
157
|
-
- **
|
|
158
|
-
- **
|
|
159
|
-
- **
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
- **
|
|
164
|
-
- **
|
|
165
|
-
- **
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
'
|
|
231
|
-
'
|
|
232
|
-
'
|
|
233
|
-
'
|
|
234
|
-
'
|
|
235
|
-
'
|
|
236
|
-
'
|
|
237
|
-
'
|
|
238
|
-
'
|
|
239
|
-
'
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
.
|
|
353
|
-
.
|
|
354
|
-
.
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (content.includes('###
|
|
375
|
-
if (content.includes('###
|
|
376
|
-
if (content.includes('###
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
if (diffContent && diffContent.includes('
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
fullExplanation += `##
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
#
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
'
|
|
532
|
-
'
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
1
|
+
import type { Violation, Analysis, Fix } from '../types/index.js';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import { ErrorHandler, APIError, ErrorType } from '../core/error-handler.js';
|
|
4
|
+
import { logger } from '../core/debug-logger.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Gemini 2.5 Pro code fixer for local files and repositories
|
|
8
|
+
* Works with any code (GitHub or not, committed or uncommitted)
|
|
9
|
+
*/
|
|
10
|
+
export class GeminiCodeFixer {
|
|
11
|
+
private apiKey: string;
|
|
12
|
+
private baseUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent';
|
|
13
|
+
private categoryLogger: ReturnType<typeof logger.createCategoryLogger>;
|
|
14
|
+
|
|
15
|
+
constructor(apiKey: string) {
|
|
16
|
+
this.apiKey = apiKey;
|
|
17
|
+
this.categoryLogger = logger.createCategoryLogger('gemini-code-fixer');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Generate a fix using Gemini 2.5 Pro with grounding
|
|
22
|
+
*/
|
|
23
|
+
async generateFix(violation: Violation, analysis: Analysis): Promise<Fix> {
|
|
24
|
+
const context = ErrorHandler.createContext('gemini_code_fix', {
|
|
25
|
+
feature: violation.feature,
|
|
26
|
+
file: violation.file,
|
|
27
|
+
browser: violation.browser
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
this.categoryLogger.info('Generating code fix', {
|
|
32
|
+
feature: violation.feature,
|
|
33
|
+
file: violation.file,
|
|
34
|
+
strategy: analysis.fixStrategy
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Read the current file content
|
|
38
|
+
const fileContent = await this.readFileContent(violation.file);
|
|
39
|
+
|
|
40
|
+
// Build the fix prompt with file context
|
|
41
|
+
const prompt = this.buildFixPrompt(violation, analysis, fileContent);
|
|
42
|
+
|
|
43
|
+
const response = await ErrorHandler.withRetry(
|
|
44
|
+
() => this.makeApiCall(prompt),
|
|
45
|
+
{
|
|
46
|
+
maxRetries: 2,
|
|
47
|
+
retryableErrors: [ErrorType.NETWORK, ErrorType.TIMEOUT, ErrorType.RATE_LIMIT, ErrorType.SERVER_ERROR]
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const data = await response.json();
|
|
52
|
+
|
|
53
|
+
// Validate response structure
|
|
54
|
+
ErrorHandler.validateAPIResponse(data, ['candidates']);
|
|
55
|
+
|
|
56
|
+
if (!data.candidates || data.candidates.length === 0) {
|
|
57
|
+
throw new APIError(
|
|
58
|
+
'No fix candidates returned from Gemini API',
|
|
59
|
+
ErrorType.VALIDATION,
|
|
60
|
+
{
|
|
61
|
+
suggestions: [
|
|
62
|
+
'Try rephrasing the fix request',
|
|
63
|
+
'Check if the code is valid',
|
|
64
|
+
'Try again with a different approach'
|
|
65
|
+
],
|
|
66
|
+
context
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const candidate = data.candidates[0];
|
|
72
|
+
const content = candidate.content?.parts?.[0]?.text;
|
|
73
|
+
|
|
74
|
+
if (!content) {
|
|
75
|
+
throw new APIError(
|
|
76
|
+
'Empty fix content returned from Gemini API',
|
|
77
|
+
ErrorType.VALIDATION,
|
|
78
|
+
{
|
|
79
|
+
suggestions: [
|
|
80
|
+
'Try the fix generation again',
|
|
81
|
+
'Check if the violation data is complete',
|
|
82
|
+
'Verify API key permissions'
|
|
83
|
+
],
|
|
84
|
+
context
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Parse the fix response and generate proper diff
|
|
90
|
+
const fix = await this.parseFixResponse(content, violation, analysis, fileContent);
|
|
91
|
+
|
|
92
|
+
this.categoryLogger.info('Code fix generated successfully', {
|
|
93
|
+
feature: violation.feature,
|
|
94
|
+
confidence: fix.confidence,
|
|
95
|
+
hasPreview: fix.preview.length > 0
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return fix;
|
|
99
|
+
|
|
100
|
+
} catch (error) {
|
|
101
|
+
const apiError = ErrorHandler.handleAPIError(error, context);
|
|
102
|
+
this.categoryLogger.error('Code fix generation failed', { error: apiError });
|
|
103
|
+
throw apiError;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Make API call to Gemini 2.5 Pro with grounding
|
|
109
|
+
*/
|
|
110
|
+
private async makeApiCall(prompt: string): Promise<Response> {
|
|
111
|
+
const response = await fetch(this.baseUrl, {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: {
|
|
114
|
+
'x-goog-api-key': this.apiKey,
|
|
115
|
+
'Content-Type': 'application/json'
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
contents: [{
|
|
119
|
+
parts: [{ text: prompt }]
|
|
120
|
+
}],
|
|
121
|
+
tools: [{
|
|
122
|
+
googleSearchRetrieval: {
|
|
123
|
+
dynamicRetrievalConfig: {
|
|
124
|
+
mode: 'MODE_DYNAMIC',
|
|
125
|
+
dynamicThreshold: 0.7
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}],
|
|
129
|
+
generationConfig: {
|
|
130
|
+
temperature: 0.1,
|
|
131
|
+
topK: 40,
|
|
132
|
+
topP: 0.95,
|
|
133
|
+
maxOutputTokens: 4096,
|
|
134
|
+
candidateCount: 1
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (!response.ok) {
|
|
140
|
+
const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
141
|
+
(error as any).response = response;
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return response;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Build comprehensive fix prompt for Gemini 2.5 Pro
|
|
150
|
+
*/
|
|
151
|
+
private buildFixPrompt(violation: Violation, analysis: Analysis, fileContent: string): string {
|
|
152
|
+
return `You are an expert web developer tasked with fixing browser compatibility issues. Generate a precise code fix with proper diff format.
|
|
153
|
+
|
|
154
|
+
## COMPATIBILITY ISSUE
|
|
155
|
+
- **Feature**: ${violation.feature}
|
|
156
|
+
- **File**: ${violation.file} (line ${violation.line})
|
|
157
|
+
- **Unsupported Browser**: ${violation.browser} ${violation.required}
|
|
158
|
+
- **Baseline Status**: ${violation.baselineStatus}
|
|
159
|
+
- **Current Code Context**: ${violation.context}
|
|
160
|
+
|
|
161
|
+
## ANALYSIS INSIGHTS
|
|
162
|
+
- **Fix Strategy**: ${analysis.fixStrategy}
|
|
163
|
+
- **User Impact**: ${analysis.userImpact}
|
|
164
|
+
- **Market Share Affected**: ${(analysis.marketShare * 100).toFixed(1)}%
|
|
165
|
+
- **Best Practices**: ${analysis.bestPractices.join(', ')}
|
|
166
|
+
|
|
167
|
+
## CURRENT FILE CONTENT
|
|
168
|
+
\`\`\`${this.getFileExtension(violation.file)}
|
|
169
|
+
${fileContent}
|
|
170
|
+
\`\`\`
|
|
171
|
+
|
|
172
|
+
## REQUIREMENTS
|
|
173
|
+
1. **Fix the compatibility issue** using ${analysis.fixStrategy}
|
|
174
|
+
2. **Preserve all existing functionality** - no breaking changes
|
|
175
|
+
3. **Add proper fallbacks** for ${violation.browser} ${violation.required}
|
|
176
|
+
4. **Follow best practices**: ${analysis.bestPractices.join(', ')}
|
|
177
|
+
5. **Generate a unified diff** showing exactly what changes to make
|
|
178
|
+
6. **Provide clear explanation** of the fix approach
|
|
179
|
+
|
|
180
|
+
## OUTPUT FORMAT
|
|
181
|
+
Please provide your response in this exact format:
|
|
182
|
+
|
|
183
|
+
### EXPLANATION
|
|
184
|
+
[Explain the fix approach and why it works]
|
|
185
|
+
|
|
186
|
+
### DIFF
|
|
187
|
+
\`\`\`diff
|
|
188
|
+
--- a/${violation.file}
|
|
189
|
+
+++ b/${violation.file}
|
|
190
|
+
@@ -[start_line],[num_lines] +[start_line],[num_lines] @@
|
|
191
|
+
[unified diff content showing the exact changes]
|
|
192
|
+
\`\`\`
|
|
193
|
+
|
|
194
|
+
### PREVIEW
|
|
195
|
+
\`\`\`${this.getFileExtension(violation.file)}
|
|
196
|
+
[Show the key changed sections with context]
|
|
197
|
+
\`\`\`
|
|
198
|
+
|
|
199
|
+
### TESTING
|
|
200
|
+
[Suggest how to test the fix works in ${violation.browser} ${violation.required}]
|
|
201
|
+
|
|
202
|
+
Focus on creating a production-ready fix that maintains compatibility across all browsers while adding proper support for ${violation.browser} ${violation.required}.`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Read file content with error handling
|
|
207
|
+
*/
|
|
208
|
+
private async readFileContent(filePath: string): Promise<string> {
|
|
209
|
+
try {
|
|
210
|
+
return await fs.readFile(filePath, 'utf-8');
|
|
211
|
+
} catch (error) {
|
|
212
|
+
this.categoryLogger.warn('Could not read file content', {
|
|
213
|
+
file: filePath,
|
|
214
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Return empty content if file can't be read
|
|
218
|
+
return `// File content could not be read: ${filePath}`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Get file extension for syntax highlighting
|
|
224
|
+
*/
|
|
225
|
+
private getFileExtension(filePath: string): string {
|
|
226
|
+
const ext = filePath.split('.').pop()?.toLowerCase();
|
|
227
|
+
|
|
228
|
+
const extensionMap: Record<string, string> = {
|
|
229
|
+
'js': 'javascript',
|
|
230
|
+
'jsx': 'javascript',
|
|
231
|
+
'ts': 'typescript',
|
|
232
|
+
'tsx': 'typescript',
|
|
233
|
+
'vue': 'vue',
|
|
234
|
+
'svelte': 'svelte',
|
|
235
|
+
'css': 'css',
|
|
236
|
+
'scss': 'scss',
|
|
237
|
+
'sass': 'sass',
|
|
238
|
+
'html': 'html',
|
|
239
|
+
'htm': 'html'
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
return extensionMap[ext || ''] || 'text';
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Parse Gemini's fix response and create Fix object
|
|
247
|
+
*/
|
|
248
|
+
private async parseFixResponse(
|
|
249
|
+
content: string,
|
|
250
|
+
violation: Violation,
|
|
251
|
+
analysis: Analysis,
|
|
252
|
+
originalContent: string
|
|
253
|
+
): Promise<Fix> {
|
|
254
|
+
try {
|
|
255
|
+
// Extract sections from the response
|
|
256
|
+
const explanation = this.extractSection(content, 'EXPLANATION');
|
|
257
|
+
const diffContent = this.extractSection(content, 'DIFF');
|
|
258
|
+
const preview = this.extractSection(content, 'PREVIEW');
|
|
259
|
+
const testing = this.extractSection(content, 'TESTING');
|
|
260
|
+
|
|
261
|
+
// Clean up the diff content
|
|
262
|
+
const cleanDiff = this.cleanDiffContent(diffContent);
|
|
263
|
+
|
|
264
|
+
// Generate a human-readable preview if not provided
|
|
265
|
+
const finalPreview = preview || this.generatePreviewFromDiff(cleanDiff, originalContent);
|
|
266
|
+
|
|
267
|
+
// Calculate confidence based on response quality
|
|
268
|
+
const confidence = this.calculateFixConfidence(content, diffContent);
|
|
269
|
+
|
|
270
|
+
// Create comprehensive explanation
|
|
271
|
+
const fullExplanation = this.buildFullExplanation(
|
|
272
|
+
violation,
|
|
273
|
+
analysis,
|
|
274
|
+
explanation,
|
|
275
|
+
testing
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
violation,
|
|
280
|
+
analysis,
|
|
281
|
+
patch: cleanDiff,
|
|
282
|
+
explanation: fullExplanation,
|
|
283
|
+
filePath: violation.file,
|
|
284
|
+
preview: finalPreview,
|
|
285
|
+
confidence,
|
|
286
|
+
testable: true
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
} catch (error) {
|
|
290
|
+
this.categoryLogger.error('Failed to parse fix response', { error });
|
|
291
|
+
|
|
292
|
+
// Return a basic fix with the raw content
|
|
293
|
+
return {
|
|
294
|
+
violation,
|
|
295
|
+
analysis,
|
|
296
|
+
patch: this.generateBasicDiff(violation.file, content),
|
|
297
|
+
explanation: `Fix generated for ${violation.feature} compatibility issue.\n\n${content}`,
|
|
298
|
+
filePath: violation.file,
|
|
299
|
+
preview: content.substring(0, 500) + (content.length > 500 ? '...' : ''),
|
|
300
|
+
confidence: 0.6,
|
|
301
|
+
testable: true
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Extract a specific section from the response
|
|
308
|
+
*/
|
|
309
|
+
private extractSection(content: string, sectionName: string): string {
|
|
310
|
+
const regex = new RegExp(`### ${sectionName}\\s*\\n([\\s\\S]*?)(?=\\n### |$)`, 'i');
|
|
311
|
+
const match = content.match(regex);
|
|
312
|
+
|
|
313
|
+
if (match && match[1]) {
|
|
314
|
+
return match[1].trim();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return '';
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Clean and validate diff content
|
|
322
|
+
*/
|
|
323
|
+
private cleanDiffContent(diffContent: string): string {
|
|
324
|
+
if (!diffContent) {
|
|
325
|
+
return '';
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Remove code block markers if present
|
|
329
|
+
let cleaned = diffContent.replace(/^```diff\\n|```$/gm, '').trim();
|
|
330
|
+
|
|
331
|
+
// Ensure it starts with proper diff headers
|
|
332
|
+
if (!cleaned.startsWith('---') && !cleaned.startsWith('@@')) {
|
|
333
|
+
// If it's just the diff content without headers, add basic headers
|
|
334
|
+
cleaned = `--- a/file\n+++ b/file\n${cleaned}`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return cleaned;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Generate preview from diff content
|
|
342
|
+
*/
|
|
343
|
+
private generatePreviewFromDiff(diffContent: string, _originalContent: string): string {
|
|
344
|
+
if (!diffContent) {
|
|
345
|
+
return 'No preview available';
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
// Extract added lines from diff
|
|
350
|
+
const addedLines = diffContent
|
|
351
|
+
.split('\n')
|
|
352
|
+
.filter(line => line.startsWith('+') && !line.startsWith('+++'))
|
|
353
|
+
.map(line => line.substring(1))
|
|
354
|
+
.join('\n');
|
|
355
|
+
|
|
356
|
+
if (addedLines) {
|
|
357
|
+
return `Changes to be applied:\n\n${addedLines}`;
|
|
358
|
+
}
|
|
359
|
+
} catch (error) {
|
|
360
|
+
// Fallback to showing first part of diff
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return diffContent.substring(0, 300) + (diffContent.length > 300 ? '...' : '');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Calculate confidence score based on response quality
|
|
368
|
+
*/
|
|
369
|
+
private calculateFixConfidence(content: string, diffContent: string): number {
|
|
370
|
+
let confidence = 0.5; // Base confidence
|
|
371
|
+
|
|
372
|
+
// Check if response has proper structure
|
|
373
|
+
if (content.includes('### EXPLANATION')) confidence += 0.1;
|
|
374
|
+
if (content.includes('### DIFF')) confidence += 0.1;
|
|
375
|
+
if (content.includes('### PREVIEW')) confidence += 0.1;
|
|
376
|
+
if (content.includes('### TESTING')) confidence += 0.1;
|
|
377
|
+
|
|
378
|
+
// Check diff quality
|
|
379
|
+
if (diffContent && diffContent.includes('@@')) confidence += 0.1;
|
|
380
|
+
if (diffContent && (diffContent.includes('+') || diffContent.includes('-'))) confidence += 0.1;
|
|
381
|
+
|
|
382
|
+
return Math.min(confidence, 0.9); // Cap at 0.9
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Build comprehensive explanation
|
|
387
|
+
*/
|
|
388
|
+
private buildFullExplanation(
|
|
389
|
+
violation: Violation,
|
|
390
|
+
analysis: Analysis,
|
|
391
|
+
explanation: string,
|
|
392
|
+
testing: string
|
|
393
|
+
): string {
|
|
394
|
+
let fullExplanation = `Fixed ${violation.feature} compatibility issue in ${violation.file}\n\n`;
|
|
395
|
+
|
|
396
|
+
if (explanation) {
|
|
397
|
+
fullExplanation += `## Fix Approach\n${explanation}\n\n`;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
fullExplanation += `## Strategy Applied\n${analysis.fixStrategy}\n\n`;
|
|
401
|
+
fullExplanation += `## Browser Support\nThis fix ensures compatibility with ${violation.browser} ${violation.required} and newer versions.\n\n`;
|
|
402
|
+
|
|
403
|
+
if (testing) {
|
|
404
|
+
fullExplanation += `## Testing\n${testing}\n\n`;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
fullExplanation += `## Best Practices Applied\n${analysis.bestPractices.map(practice => `• ${practice}`).join('\n')}`;
|
|
408
|
+
|
|
409
|
+
return fullExplanation;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Generate basic diff as fallback
|
|
414
|
+
*/
|
|
415
|
+
private generateBasicDiff(filePath: string, content: string): string {
|
|
416
|
+
return `--- a/${filePath}
|
|
417
|
+
+++ b/${filePath}
|
|
418
|
+
@@ -1,1 +1,1 @@
|
|
419
|
+
-// Original code (manual review required)
|
|
420
|
+
+// Fixed code: ${content.substring(0, 100)}${content.length > 100 ? '...' : ''}
|
|
421
|
+
|
|
422
|
+
# Manual fix required - please review the generated content above
|
|
423
|
+
# and apply the appropriate changes to your code.`;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Test API connectivity
|
|
428
|
+
*/
|
|
429
|
+
async testConnection(): Promise<{ success: boolean; error?: string; errorType?: ErrorType }> {
|
|
430
|
+
try {
|
|
431
|
+
const testPrompt = 'Generate a simple "Hello, World!" comment in JavaScript.';
|
|
432
|
+
const response = await this.makeApiCall(testPrompt);
|
|
433
|
+
|
|
434
|
+
const data = await response.json();
|
|
435
|
+
|
|
436
|
+
if (data.candidates && data.candidates.length > 0) {
|
|
437
|
+
return { success: true };
|
|
438
|
+
} else {
|
|
439
|
+
return {
|
|
440
|
+
success: false,
|
|
441
|
+
error: 'API responded but returned no content',
|
|
442
|
+
errorType: ErrorType.VALIDATION
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
} catch (error) {
|
|
446
|
+
const apiError = ErrorHandler.handleAPIError(error);
|
|
447
|
+
|
|
448
|
+
return {
|
|
449
|
+
success: false,
|
|
450
|
+
error: apiError.message,
|
|
451
|
+
errorType: apiError.type
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Validate API key format
|
|
458
|
+
*/
|
|
459
|
+
public static validateApiKey(apiKey: string): boolean {
|
|
460
|
+
// Gemini API keys typically start with 'AIza' and are 39+ characters long
|
|
461
|
+
return /^AIza[A-Za-z0-9_-]{35,}$/.test(apiKey) || apiKey.length >= 20;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Generate multiple fix options for complex issues
|
|
466
|
+
*/
|
|
467
|
+
async generateFixOptions(violation: Violation, analysis: Analysis): Promise<Fix[]> {
|
|
468
|
+
const fixes: Fix[] = [];
|
|
469
|
+
|
|
470
|
+
try {
|
|
471
|
+
// Generate primary fix
|
|
472
|
+
const primaryFix = await this.generateFix(violation, analysis);
|
|
473
|
+
fixes.push(primaryFix);
|
|
474
|
+
|
|
475
|
+
// Generate alternative approaches if confidence is low
|
|
476
|
+
if (primaryFix.confidence < 0.7) {
|
|
477
|
+
this.categoryLogger.info('Generating alternative fix approaches', {
|
|
478
|
+
feature: violation.feature,
|
|
479
|
+
primaryConfidence: primaryFix.confidence
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
const alternativeFix = await this.generateAlternativeFix(violation, analysis);
|
|
483
|
+
if (alternativeFix) {
|
|
484
|
+
fixes.push(alternativeFix);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
} catch (error) {
|
|
489
|
+
this.categoryLogger.error('Failed to generate fix options', { error });
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return fixes;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Generate alternative fix approach
|
|
498
|
+
*/
|
|
499
|
+
private async generateAlternativeFix(violation: Violation, analysis: Analysis): Promise<Fix | null> {
|
|
500
|
+
try {
|
|
501
|
+
const fileContent = await this.readFileContent(violation.file);
|
|
502
|
+
|
|
503
|
+
// Build alternative prompt with different strategy
|
|
504
|
+
const alternativePrompt = this.buildAlternativeFixPrompt(violation, analysis, fileContent);
|
|
505
|
+
|
|
506
|
+
const response = await this.makeApiCall(alternativePrompt);
|
|
507
|
+
const data = await response.json();
|
|
508
|
+
|
|
509
|
+
if (data.candidates && data.candidates.length > 0) {
|
|
510
|
+
const content = data.candidates[0].content?.parts?.[0]?.text;
|
|
511
|
+
if (content) {
|
|
512
|
+
const fix = await this.parseFixResponse(content, violation, analysis, fileContent);
|
|
513
|
+
fix.explanation = `Alternative approach: ${fix.explanation}`;
|
|
514
|
+
return fix;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
} catch (error) {
|
|
519
|
+
this.categoryLogger.warn('Failed to generate alternative fix', { error });
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return null;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Build alternative fix prompt with different strategy
|
|
527
|
+
*/
|
|
528
|
+
private buildAlternativeFixPrompt(violation: Violation, analysis: Analysis, fileContent: string): string {
|
|
529
|
+
const alternativeStrategies = {
|
|
530
|
+
'progressive enhancement with @supports': 'feature detection with JavaScript',
|
|
531
|
+
'feature detection with polyfills': 'progressive enhancement with @supports',
|
|
532
|
+
'graceful degradation': 'polyfill-based approach'
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
const altStrategy = alternativeStrategies[analysis.fixStrategy as keyof typeof alternativeStrategies] || 'alternative progressive enhancement';
|
|
536
|
+
|
|
537
|
+
return this.buildFixPrompt(violation, { ...analysis, fixStrategy: altStrategy }, fileContent);
|
|
538
|
+
}
|
|
539
|
+
}
|