baseguard 1.0.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.
- package/.eslintrc.json +25 -0
- package/.prettierrc +8 -0
- package/README.md +94 -0
- package/bin/base.js +494 -0
- package/dist/ai/fix-manager.d.ts +67 -0
- package/dist/ai/fix-manager.d.ts.map +1 -0
- package/dist/ai/fix-manager.js +326 -0
- package/dist/ai/fix-manager.js.map +1 -0
- package/dist/ai/gemini-analyzer.d.ts +116 -0
- package/dist/ai/gemini-analyzer.d.ts.map +1 -0
- package/dist/ai/gemini-analyzer.js +572 -0
- package/dist/ai/gemini-analyzer.js.map +1 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +5 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/jules-implementer.d.ts +115 -0
- package/dist/ai/jules-implementer.d.ts.map +1 -0
- package/dist/ai/jules-implementer.js +387 -0
- package/dist/ai/jules-implementer.js.map +1 -0
- package/dist/commands/automation.d.ts +5 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +305 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/check.d.ts +9 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +113 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/config.d.ts +11 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +324 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/fix.d.ts +9 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +207 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +125 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/core/api-key-manager.d.ts +83 -0
- package/dist/core/api-key-manager.d.ts.map +1 -0
- package/dist/core/api-key-manager.js +244 -0
- package/dist/core/api-key-manager.js.map +1 -0
- package/dist/core/baseguard.d.ts +46 -0
- package/dist/core/baseguard.d.ts.map +1 -0
- package/dist/core/baseguard.js +132 -0
- package/dist/core/baseguard.js.map +1 -0
- package/dist/core/baseline-checker.d.ts +63 -0
- package/dist/core/baseline-checker.d.ts.map +1 -0
- package/dist/core/baseline-checker.js +502 -0
- package/dist/core/baseline-checker.js.map +1 -0
- package/dist/core/cache-manager.d.ts +88 -0
- package/dist/core/cache-manager.d.ts.map +1 -0
- package/dist/core/cache-manager.js +213 -0
- package/dist/core/cache-manager.js.map +1 -0
- package/dist/core/configuration.d.ts +140 -0
- package/dist/core/configuration.d.ts.map +1 -0
- package/dist/core/configuration.js +474 -0
- package/dist/core/configuration.js.map +1 -0
- package/dist/core/directory-filter.d.ts +90 -0
- package/dist/core/directory-filter.d.ts.map +1 -0
- package/dist/core/directory-filter.js +319 -0
- package/dist/core/directory-filter.js.map +1 -0
- package/dist/core/error-handler.d.ts +110 -0
- package/dist/core/error-handler.d.ts.map +1 -0
- package/dist/core/error-handler.js +392 -0
- package/dist/core/error-handler.js.map +1 -0
- package/dist/core/file-processor.d.ts +80 -0
- package/dist/core/file-processor.d.ts.map +1 -0
- package/dist/core/file-processor.js +259 -0
- package/dist/core/file-processor.js.map +1 -0
- package/dist/core/gitignore-manager.d.ts +44 -0
- package/dist/core/gitignore-manager.d.ts.map +1 -0
- package/dist/core/gitignore-manager.js +147 -0
- package/dist/core/gitignore-manager.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lazy-loader.d.ts +68 -0
- package/dist/core/lazy-loader.d.ts.map +1 -0
- package/dist/core/lazy-loader.js +260 -0
- package/dist/core/lazy-loader.js.map +1 -0
- package/dist/core/memory-manager.d.ts +1 -0
- package/dist/core/memory-manager.d.ts.map +1 -0
- package/dist/core/memory-manager.js +2 -0
- package/dist/core/memory-manager.js.map +1 -0
- package/dist/core/startup-optimizer.d.ts +45 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -0
- package/dist/core/startup-optimizer.js +140 -0
- package/dist/core/startup-optimizer.js.map +1 -0
- package/dist/git/automation-engine.d.ts +58 -0
- package/dist/git/automation-engine.d.ts.map +1 -0
- package/dist/git/automation-engine.js +318 -0
- package/dist/git/automation-engine.js.map +1 -0
- package/dist/git/github-manager.d.ts +71 -0
- package/dist/git/github-manager.d.ts.map +1 -0
- package/dist/git/github-manager.js +226 -0
- package/dist/git/github-manager.js.map +1 -0
- package/dist/git/hook-manager.d.ts +43 -0
- package/dist/git/hook-manager.d.ts.map +1 -0
- package/dist/git/hook-manager.js +191 -0
- package/dist/git/hook-manager.js.map +1 -0
- package/dist/git/index.d.ts +4 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +5 -0
- package/dist/git/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/feature-validator.d.ts +60 -0
- package/dist/parsers/feature-validator.d.ts.map +1 -0
- package/dist/parsers/feature-validator.js +483 -0
- package/dist/parsers/feature-validator.js.map +1 -0
- package/dist/parsers/index.d.ts +8 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +9 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/parser-manager.d.ts +103 -0
- package/dist/parsers/parser-manager.d.ts.map +1 -0
- package/dist/parsers/parser-manager.js +321 -0
- package/dist/parsers/parser-manager.js.map +1 -0
- package/dist/parsers/parser.d.ts +23 -0
- package/dist/parsers/parser.d.ts.map +1 -0
- package/dist/parsers/parser.js +6 -0
- package/dist/parsers/parser.js.map +1 -0
- package/dist/parsers/react-parser.d.ts +22 -0
- package/dist/parsers/react-parser.d.ts.map +1 -0
- package/dist/parsers/react-parser.js +307 -0
- package/dist/parsers/react-parser.js.map +1 -0
- package/dist/parsers/svelte-parser.d.ts +33 -0
- package/dist/parsers/svelte-parser.d.ts.map +1 -0
- package/dist/parsers/svelte-parser.js +408 -0
- package/dist/parsers/svelte-parser.js.map +1 -0
- package/dist/parsers/vanilla-parser.d.ts +31 -0
- package/dist/parsers/vanilla-parser.d.ts.map +1 -0
- package/dist/parsers/vanilla-parser.js +590 -0
- package/dist/parsers/vanilla-parser.js.map +1 -0
- package/dist/parsers/vue-parser.d.ts +9 -0
- package/dist/parsers/vue-parser.d.ts.map +1 -0
- package/dist/parsers/vue-parser.js +16 -0
- package/dist/parsers/vue-parser.js.map +1 -0
- package/dist/terminal-header.d.ts +12 -0
- package/dist/terminal-header.js +45 -0
- package/dist/types/index.d.ts +83 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/components.d.ts +133 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/components.js +482 -0
- package/dist/ui/components.js.map +1 -0
- package/dist/ui/help.d.ts +11 -0
- package/dist/ui/help.d.ts.map +1 -0
- package/dist/ui/help.js +161 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +5 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/prompts.d.ts +63 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +611 -0
- package/dist/ui/prompts.js.map +1 -0
- package/dist/ui/terminal-header.d.ts +13 -0
- package/dist/ui/terminal-header.d.ts.map +1 -0
- package/dist/ui/terminal-header.js +46 -0
- package/dist/ui/terminal-header.js.map +1 -0
- package/package.json +80 -0
- package/src/ai/__tests__/gemini-analyzer.test.ts +181 -0
- package/src/ai/fix-manager.ts +362 -0
- package/src/ai/gemini-analyzer.ts +671 -0
- package/src/ai/index.ts +4 -0
- package/src/ai/jules-implementer.ts +459 -0
- package/src/commands/automation.ts +344 -0
- package/src/commands/check.ts +299 -0
- package/src/commands/config.ts +365 -0
- package/src/commands/fix.ts +234 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/init.ts +142 -0
- package/src/commands/status.ts +0 -0
- package/src/core/api-key-manager.ts +298 -0
- package/src/core/baseguard.ts +742 -0
- package/src/core/baseline-checker.ts +563 -0
- package/src/core/cache-manager.ts +270 -0
- package/src/core/configuration-recovery.ts +676 -0
- package/src/core/configuration.ts +559 -0
- package/src/core/debug-logger.ts +590 -0
- package/src/core/directory-filter.ts +421 -0
- package/src/core/error-handler.ts +517 -0
- package/src/core/file-processor.ts +331 -0
- package/src/core/gitignore-manager.ts +169 -0
- package/src/core/graceful-degradation-manager.ts +596 -0
- package/src/core/index.ts +13 -0
- package/src/core/lazy-loader.ts +307 -0
- package/src/core/logger.ts +0 -0
- package/src/core/memory-manager.ts +294 -0
- package/src/core/startup-optimizer.ts +173 -0
- package/src/core/system-error-handler.ts +746 -0
- package/src/git/automation-engine.ts +361 -0
- package/src/git/github-manager.ts +260 -0
- package/src/git/hook-manager.ts +210 -0
- package/src/git/index.ts +4 -0
- package/src/index.ts +8 -0
- package/src/parsers/feature-validator.ts +559 -0
- package/src/parsers/index.ts +8 -0
- package/src/parsers/parser-manager.ts +419 -0
- package/src/parsers/parser.ts +26 -0
- package/src/parsers/react-parser-optimized.ts +161 -0
- package/src/parsers/react-parser.ts +359 -0
- package/src/parsers/svelte-parser.ts +506 -0
- package/src/parsers/vanilla-parser.ts +682 -0
- package/src/parsers/vue-parser.ts +472 -0
- package/src/types/index.ts +92 -0
- package/src/ui/components.ts +567 -0
- package/src/ui/help.ts +193 -0
- package/src/ui/index.ts +4 -0
- package/src/ui/prompts.ts +688 -0
- package/src/ui/terminal-header.ts +59 -0
- package/test-config-commands.js +56 -0
- package/test-header-simple.js +33 -0
- package/test-terminal-header.js +12 -0
- package/test-ui.js +29 -0
- package/tests/e2e/baseguard.e2e.test.ts +516 -0
- package/tests/e2e/cross-platform.e2e.test.ts +420 -0
- package/tests/e2e/git-integration.e2e.test.ts +487 -0
- package/tests/fixtures/react-project/package.json +14 -0
- package/tests/fixtures/react-project/src/App.css +76 -0
- package/tests/fixtures/react-project/src/App.tsx +77 -0
- package/tests/fixtures/svelte-project/package.json +11 -0
- package/tests/fixtures/svelte-project/src/App.svelte +369 -0
- package/tests/fixtures/vanilla-project/index.html +76 -0
- package/tests/fixtures/vanilla-project/script.js +331 -0
- package/tests/fixtures/vanilla-project/styles.css +359 -0
- package/tests/fixtures/vue-project/package.json +12 -0
- package/tests/fixtures/vue-project/src/App.vue +216 -0
- package/tsconfig.json +36 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import * as Table from 'cli-table3';
|
|
3
|
+
import boxen from 'boxen';
|
|
4
|
+
import ora, { type Ora } from 'ora';
|
|
5
|
+
import type { Violation, Analysis, Fix, Configuration } from '../types/index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Color scheme for consistent CLI output
|
|
9
|
+
*/
|
|
10
|
+
export const Colors = {
|
|
11
|
+
primary: chalk.cyan,
|
|
12
|
+
success: chalk.green,
|
|
13
|
+
error: chalk.red,
|
|
14
|
+
warning: chalk.yellow,
|
|
15
|
+
info: chalk.blue,
|
|
16
|
+
muted: chalk.gray,
|
|
17
|
+
highlight: chalk.magenta,
|
|
18
|
+
feature: chalk.white.bold,
|
|
19
|
+
file: chalk.dim,
|
|
20
|
+
browser: chalk.yellow,
|
|
21
|
+
baseline: chalk.cyan
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* UI components for beautiful CLI output
|
|
26
|
+
*/
|
|
27
|
+
export { Prompts } from './prompts.js';
|
|
28
|
+
|
|
29
|
+
export class UIComponents {
|
|
30
|
+
/**
|
|
31
|
+
* Display violations grouped by file with clear visual hierarchy
|
|
32
|
+
*/
|
|
33
|
+
static showViolations(violations: Violation[]): void {
|
|
34
|
+
if (violations.length === 0) {
|
|
35
|
+
this.showSuccessBox('No compatibility violations found! 🎉');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.showSectionHeader(`Found ${violations.length} compatibility violation${violations.length === 1 ? '' : 's'}`);
|
|
40
|
+
|
|
41
|
+
// Group violations by file
|
|
42
|
+
const violationsByFile = this.groupViolationsByFile(violations);
|
|
43
|
+
|
|
44
|
+
Object.entries(violationsByFile).forEach(([file, fileViolations]) => {
|
|
45
|
+
console.log(`\n${Colors.file.bold(file)}`);
|
|
46
|
+
console.log(Colors.muted('─'.repeat(Math.min(file.length, 60))));
|
|
47
|
+
|
|
48
|
+
fileViolations.forEach((violation, index) => {
|
|
49
|
+
this.showSingleViolation(violation, index + 1);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Show summary
|
|
54
|
+
this.showViolationSummary(violations);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Display a single violation with context and details
|
|
59
|
+
*/
|
|
60
|
+
static showSingleViolation(violation: Violation, index: number): void {
|
|
61
|
+
const lineInfo = `${Colors.muted('Line')} ${Colors.highlight(violation.line.toString())}`;
|
|
62
|
+
const featureInfo = `${Colors.feature(violation.feature)}`;
|
|
63
|
+
const browserInfo = `${Colors.browser(violation.browser)} ${violation.required}`;
|
|
64
|
+
const baselineInfo = this.formatBaselineStatus(violation.baselineStatus);
|
|
65
|
+
|
|
66
|
+
console.log(`\n ${Colors.error('●')} ${featureInfo} ${Colors.muted('at')} ${lineInfo}`);
|
|
67
|
+
console.log(` ${Colors.muted('Browser:')} ${browserInfo}`);
|
|
68
|
+
console.log(` ${Colors.muted('Baseline:')} ${baselineInfo}`);
|
|
69
|
+
|
|
70
|
+
if (violation.reason) {
|
|
71
|
+
console.log(` ${Colors.muted('Issue:')} ${violation.reason}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Show code context with syntax highlighting
|
|
75
|
+
if (violation.context) {
|
|
76
|
+
console.log(` ${Colors.muted('Context:')}`);
|
|
77
|
+
this.showCodeContext(violation.context, violation.line, violation.column);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Show code context with basic syntax highlighting
|
|
83
|
+
*/
|
|
84
|
+
static showCodeContext(context: string, line: number, column: number): void {
|
|
85
|
+
const lines = context.split('\n');
|
|
86
|
+
const contextLines = lines.slice(Math.max(0, lines.length - 3), lines.length);
|
|
87
|
+
|
|
88
|
+
contextLines.forEach((contextLine, index) => {
|
|
89
|
+
const lineNumber = line - (contextLines.length - 1 - index);
|
|
90
|
+
const isTargetLine = lineNumber === line;
|
|
91
|
+
|
|
92
|
+
const lineNumberStr = Colors.muted(lineNumber.toString().padStart(3));
|
|
93
|
+
const prefix = isTargetLine ? Colors.error('►') : Colors.muted('│');
|
|
94
|
+
const content = isTargetLine ? Colors.highlight(contextLine) : Colors.muted(contextLine);
|
|
95
|
+
|
|
96
|
+
console.log(` ${lineNumberStr} ${prefix} ${content}`);
|
|
97
|
+
|
|
98
|
+
// Show column indicator for target line
|
|
99
|
+
if (isTargetLine && column > 0) {
|
|
100
|
+
const spaces = ' '.repeat(6 + 4 + column - 1);
|
|
101
|
+
console.log(`${spaces}${Colors.error('^')}`);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Format baseline status with appropriate colors
|
|
108
|
+
*/
|
|
109
|
+
static formatBaselineStatus(status: string): string {
|
|
110
|
+
switch (status) {
|
|
111
|
+
case 'widely':
|
|
112
|
+
return Colors.success('✓ Widely supported');
|
|
113
|
+
case 'newly':
|
|
114
|
+
return Colors.warning('⚠ Newly available');
|
|
115
|
+
case 'false':
|
|
116
|
+
return Colors.error('✗ Not baseline');
|
|
117
|
+
default:
|
|
118
|
+
return Colors.muted(`${status}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Group violations by file for organized display
|
|
124
|
+
*/
|
|
125
|
+
static groupViolationsByFile(violations: Violation[]): Record<string, Violation[]> {
|
|
126
|
+
return violations.reduce((groups, violation) => {
|
|
127
|
+
const file = violation.file;
|
|
128
|
+
if (!groups[file]) {
|
|
129
|
+
groups[file] = [];
|
|
130
|
+
}
|
|
131
|
+
groups[file].push(violation);
|
|
132
|
+
return groups;
|
|
133
|
+
}, {} as Record<string, Violation[]>);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Show violation summary with actionable next steps
|
|
138
|
+
*/
|
|
139
|
+
static showViolationSummary(violations: Violation[]): void {
|
|
140
|
+
console.log('\n');
|
|
141
|
+
this.showSectionHeader('Summary');
|
|
142
|
+
|
|
143
|
+
// Count by browser
|
|
144
|
+
const browserCounts = violations.reduce((counts, v) => {
|
|
145
|
+
const key = `${v.browser} ${v.required}`;
|
|
146
|
+
counts[key] = (counts[key] || 0) + 1;
|
|
147
|
+
return counts;
|
|
148
|
+
}, {} as Record<string, number>);
|
|
149
|
+
|
|
150
|
+
// Count by baseline status
|
|
151
|
+
const baselineCounts = violations.reduce((counts, v) => {
|
|
152
|
+
counts[v.baselineStatus] = (counts[v.baselineStatus] || 0) + 1;
|
|
153
|
+
return counts;
|
|
154
|
+
}, {} as Record<string, number>);
|
|
155
|
+
|
|
156
|
+
// Show browser breakdown
|
|
157
|
+
console.log(Colors.muted('Affected browsers:'));
|
|
158
|
+
Object.entries(browserCounts).forEach(([browser, count]) => {
|
|
159
|
+
console.log(` ${Colors.browser('●')} ${browser}: ${Colors.highlight(count.toString())} issue${count === 1 ? '' : 's'}`);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Show baseline breakdown
|
|
163
|
+
console.log(Colors.muted('\nBaseline status:'));
|
|
164
|
+
Object.entries(baselineCounts).forEach(([status, count]) => {
|
|
165
|
+
const statusDisplay = this.formatBaselineStatus(status);
|
|
166
|
+
console.log(` ${statusDisplay}: ${Colors.highlight(count.toString())} issue${count === 1 ? '' : 's'}`);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Show next steps
|
|
170
|
+
console.log(Colors.muted('\nNext steps:'));
|
|
171
|
+
this.showList([
|
|
172
|
+
`Run ${Colors.primary('base fix')} to automatically fix issues with AI`,
|
|
173
|
+
`Run ${Colors.primary('base check --strict')} to see detailed analysis`,
|
|
174
|
+
`Configure different browser targets with ${Colors.primary('base config targets')}`
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Display analysis results with sources and recommendations
|
|
180
|
+
*/
|
|
181
|
+
static showAnalysis(analysis: Analysis): void {
|
|
182
|
+
const { violation, userImpact, fixStrategy, bestPractices, sources, plainEnglish, confidence } = analysis;
|
|
183
|
+
|
|
184
|
+
console.log(`\n${Colors.highlight('🧠 AI Analysis')}`);
|
|
185
|
+
console.log(Colors.muted('─'.repeat(20)));
|
|
186
|
+
|
|
187
|
+
console.log(`${Colors.feature(violation.feature)} ${Colors.muted('in')} ${Colors.file(violation.file)}`);
|
|
188
|
+
|
|
189
|
+
if (userImpact) {
|
|
190
|
+
console.log(`\n${Colors.muted('User Impact:')} ${userImpact}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (fixStrategy) {
|
|
194
|
+
console.log(`${Colors.muted('Fix Strategy:')} ${fixStrategy}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (bestPractices.length > 0) {
|
|
198
|
+
console.log(`\n${Colors.muted('Best Practices:')}`);
|
|
199
|
+
this.showList(bestPractices);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (plainEnglish) {
|
|
203
|
+
console.log(`\n${Colors.muted('Explanation:')}`);
|
|
204
|
+
console.log(this.wrapText(plainEnglish, 70));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (sources.length > 0) {
|
|
208
|
+
console.log(`\n${Colors.muted('Sources:')}`);
|
|
209
|
+
sources.forEach(source => {
|
|
210
|
+
console.log(` ${Colors.info('🔗')} ${Colors.primary(source)}`);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const confidenceColor = confidence > 0.8 ? Colors.success : confidence > 0.6 ? Colors.warning : Colors.error;
|
|
215
|
+
console.log(`\n${Colors.muted('Confidence:')} ${confidenceColor((confidence * 100).toFixed(0) + '%')}`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Display fix preview with diff-like formatting
|
|
220
|
+
*/
|
|
221
|
+
static showFixPreview(fix: Fix): void {
|
|
222
|
+
console.log(`\n${Colors.highlight('🔧 Proposed Fix')}`);
|
|
223
|
+
console.log(Colors.muted('─'.repeat(20)));
|
|
224
|
+
|
|
225
|
+
console.log(`${Colors.file(fix.filePath)}`);
|
|
226
|
+
console.log(`${Colors.muted('Explanation:')} ${fix.explanation}`);
|
|
227
|
+
|
|
228
|
+
if (fix.patch) {
|
|
229
|
+
console.log(`\n${Colors.muted('Changes:')}`);
|
|
230
|
+
this.showDiff(fix.patch);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (fix.preview) {
|
|
234
|
+
console.log(`\n${Colors.muted('Preview:')}`);
|
|
235
|
+
console.log(this.wrapText(fix.preview, 70));
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const confidenceColor = fix.confidence > 0.8 ? Colors.success : fix.confidence > 0.6 ? Colors.warning : Colors.error;
|
|
239
|
+
console.log(`\n${Colors.muted('Confidence:')} ${confidenceColor((fix.confidence * 100).toFixed(0) + '%')}`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Display diff with syntax highlighting
|
|
244
|
+
*/
|
|
245
|
+
static showDiff(patch: string): void {
|
|
246
|
+
const lines = patch.split('\n');
|
|
247
|
+
|
|
248
|
+
lines.forEach(line => {
|
|
249
|
+
if (line.startsWith('+')) {
|
|
250
|
+
console.log(` ${Colors.success(line)}`);
|
|
251
|
+
} else if (line.startsWith('-')) {
|
|
252
|
+
console.log(` ${Colors.error(line)}`);
|
|
253
|
+
} else if (line.startsWith('@@')) {
|
|
254
|
+
console.log(` ${Colors.info(line)}`);
|
|
255
|
+
} else {
|
|
256
|
+
console.log(` ${Colors.muted(line)}`);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Show configuration in a readable format
|
|
263
|
+
*/
|
|
264
|
+
static showConfiguration(config: Configuration): void {
|
|
265
|
+
this.showSectionHeader('BaseGuard Configuration');
|
|
266
|
+
|
|
267
|
+
console.log(`${Colors.muted('Version:')} ${config.version}`);
|
|
268
|
+
|
|
269
|
+
console.log(`\n${Colors.muted('Browser Targets:')}`);
|
|
270
|
+
config.targets.forEach(target => {
|
|
271
|
+
const version = target.minVersion === 'baseline' ? Colors.baseline('baseline') :
|
|
272
|
+
target.minVersion === 'baseline-newly' ? Colors.warning('baseline-newly') :
|
|
273
|
+
Colors.highlight(target.minVersion);
|
|
274
|
+
console.log(` ${Colors.browser('●')} ${target.browser} ${version}`);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
console.log(`\n${Colors.muted('API Keys:')}`);
|
|
278
|
+
const julesStatus = config.apiKeys.jules ? Colors.success('✓ Configured') : Colors.error('✗ Not set');
|
|
279
|
+
const geminiStatus = config.apiKeys.gemini ? Colors.success('✓ Configured') : Colors.error('✗ Not set');
|
|
280
|
+
console.log(` ${Colors.muted('Jules:')} ${julesStatus}`);
|
|
281
|
+
console.log(` ${Colors.muted('Gemini:')} ${geminiStatus}`);
|
|
282
|
+
|
|
283
|
+
if (config.automation) {
|
|
284
|
+
console.log(`\n${Colors.muted('Git Automation:')}`);
|
|
285
|
+
const enabledStatus = config.automation.enabled ? Colors.success('✓ Enabled') : Colors.error('✗ Disabled');
|
|
286
|
+
console.log(` ${Colors.muted('Status:')} ${enabledStatus}`);
|
|
287
|
+
|
|
288
|
+
if (config.automation.enabled) {
|
|
289
|
+
console.log(` ${Colors.muted('Trigger:')} ${config.automation.trigger}`);
|
|
290
|
+
console.log(` ${Colors.muted('Auto-analyze:')} ${config.automation.autoAnalyze ? '✓' : '✗'}`);
|
|
291
|
+
console.log(` ${Colors.muted('Auto-fix:')} ${config.automation.autoFix ? '✓' : '✗'}`);
|
|
292
|
+
console.log(` ${Colors.muted('Block commits:')} ${config.automation.blockCommit ? '✓' : '✗'}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Wrap text to specified width
|
|
299
|
+
*/
|
|
300
|
+
static wrapText(text: string, width: number): string {
|
|
301
|
+
const words = text.split(' ');
|
|
302
|
+
const lines: string[] = [];
|
|
303
|
+
let currentLine = '';
|
|
304
|
+
|
|
305
|
+
words.forEach(word => {
|
|
306
|
+
if (currentLine.length + word.length + 1 <= width) {
|
|
307
|
+
currentLine += (currentLine ? ' ' : '') + word;
|
|
308
|
+
} else {
|
|
309
|
+
if (currentLine) lines.push(currentLine);
|
|
310
|
+
currentLine = word;
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
if (currentLine) lines.push(currentLine);
|
|
315
|
+
|
|
316
|
+
return lines.map(line => ` ${line}`).join('\n');
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Create a spinner for long-running operations
|
|
321
|
+
*/
|
|
322
|
+
static createSpinner(text: string): Ora {
|
|
323
|
+
return ora({
|
|
324
|
+
text: Colors.primary(text),
|
|
325
|
+
spinner: 'dots',
|
|
326
|
+
color: 'cyan'
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Show success message in a box
|
|
332
|
+
*/
|
|
333
|
+
static showSuccessBox(message: string): void {
|
|
334
|
+
console.log(boxen(
|
|
335
|
+
Colors.success.bold('✅ ' + message),
|
|
336
|
+
{
|
|
337
|
+
padding: 1,
|
|
338
|
+
borderStyle: 'round',
|
|
339
|
+
borderColor: 'green'
|
|
340
|
+
}
|
|
341
|
+
));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Show error message in a box
|
|
346
|
+
*/
|
|
347
|
+
static showErrorBox(message: string): void {
|
|
348
|
+
console.log(boxen(
|
|
349
|
+
Colors.error.bold('❌ ' + message),
|
|
350
|
+
{
|
|
351
|
+
padding: 1,
|
|
352
|
+
borderStyle: 'round',
|
|
353
|
+
borderColor: 'red'
|
|
354
|
+
}
|
|
355
|
+
));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Show warning message in a box
|
|
360
|
+
*/
|
|
361
|
+
static showWarningBox(message: string): void {
|
|
362
|
+
console.log(boxen(
|
|
363
|
+
Colors.warning.bold('⚠️ ' + message),
|
|
364
|
+
{
|
|
365
|
+
padding: 1,
|
|
366
|
+
borderStyle: 'round',
|
|
367
|
+
borderColor: 'yellow'
|
|
368
|
+
}
|
|
369
|
+
));
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Show info message in a box
|
|
374
|
+
*/
|
|
375
|
+
static showInfoBox(message: string): void {
|
|
376
|
+
console.log(boxen(
|
|
377
|
+
Colors.info.bold('ℹ️ ' + message),
|
|
378
|
+
{
|
|
379
|
+
padding: 1,
|
|
380
|
+
borderStyle: 'round',
|
|
381
|
+
borderColor: 'cyan'
|
|
382
|
+
}
|
|
383
|
+
));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Show a formatted header with Baseguard branding
|
|
388
|
+
*/
|
|
389
|
+
static showHeader(): void {
|
|
390
|
+
const header = `
|
|
391
|
+
${Colors.primary.bold('🛡️ Baseguard')} ${Colors.muted('- Never ship incompatible code again')}
|
|
392
|
+
${Colors.muted('━'.repeat(60))}
|
|
393
|
+
`.trim();
|
|
394
|
+
console.log(header);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Show the full terminal header with ASCII art
|
|
399
|
+
*/
|
|
400
|
+
static showFullHeader(): void {
|
|
401
|
+
try {
|
|
402
|
+
// Use the simple header for now
|
|
403
|
+
this.showTerminalHeader();
|
|
404
|
+
} catch {
|
|
405
|
+
// Fallback to simple header if terminal-header is not available
|
|
406
|
+
this.showHeader();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Show beautiful terminal header with ASCII art
|
|
412
|
+
*/
|
|
413
|
+
static showTerminalHeader(): void {
|
|
414
|
+
console.clear();
|
|
415
|
+
|
|
416
|
+
// Well-spaced ASCII art for "Baseguard" - monochrome for good contrast
|
|
417
|
+
const logo = `
|
|
418
|
+
██████╗ █████╗ ███████╗ ███████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗
|
|
419
|
+
██╔══██╗ ██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ██║ ██║ ██╔══██╗ ██╔══██╗ ██╔══██╗
|
|
420
|
+
██████╔╝ ███████║ ███████╗ █████╗ ██║ ███╗ ██║ ██║ ███████║ ██████╔╝ ██║ ██║
|
|
421
|
+
██╔══██╗ ██╔══██║ ╚════██║ ██╔══╝ ██║ ██║ ██║ ██║ ██╔══██║ ██╔══██╗ ██║ ██║
|
|
422
|
+
██████╔╝ ██║ ██║ ███████║ ███████╗ ╚██████╔╝ ╚██████╔╝ ██║ ██║ ██║ ██║ ██████╔╝
|
|
423
|
+
╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
|
|
424
|
+
`;
|
|
425
|
+
|
|
426
|
+
// Use monochrome styling for good contrast
|
|
427
|
+
console.log(chalk.bold.white(logo));
|
|
428
|
+
|
|
429
|
+
// Tagline with styling
|
|
430
|
+
console.log(
|
|
431
|
+
chalk.bold.white(' Ship Modern Code') +
|
|
432
|
+
chalk.dim(' ✨\n')
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Show a formatted section header
|
|
438
|
+
*/
|
|
439
|
+
static showSectionHeader(title: string): void {
|
|
440
|
+
console.log(`\n${Colors.highlight.bold(title)}`);
|
|
441
|
+
console.log(Colors.muted('─'.repeat(title.length)));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Create a formatted table for displaying data
|
|
446
|
+
*/
|
|
447
|
+
static createTable(headers: string[]): any {
|
|
448
|
+
return new (Table as any)({
|
|
449
|
+
head: headers.map(h => Colors.primary.bold(h)),
|
|
450
|
+
style: {
|
|
451
|
+
head: [],
|
|
452
|
+
border: ['dim'],
|
|
453
|
+
'padding-left': 1,
|
|
454
|
+
'padding-right': 1
|
|
455
|
+
},
|
|
456
|
+
chars: {
|
|
457
|
+
'top': '─',
|
|
458
|
+
'top-mid': '┬',
|
|
459
|
+
'top-left': '┌',
|
|
460
|
+
'top-right': '┐',
|
|
461
|
+
'bottom': '─',
|
|
462
|
+
'bottom-mid': '┴',
|
|
463
|
+
'bottom-left': '└',
|
|
464
|
+
'bottom-right': '┘',
|
|
465
|
+
'left': '│',
|
|
466
|
+
'left-mid': '├',
|
|
467
|
+
'mid': '─',
|
|
468
|
+
'mid-mid': '┼',
|
|
469
|
+
'right': '│',
|
|
470
|
+
'right-mid': '┤',
|
|
471
|
+
'middle': '│'
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Show a progress indicator
|
|
478
|
+
*/
|
|
479
|
+
static showProgress(current: number, total: number, operation: string): void {
|
|
480
|
+
const percentage = Math.round((current / total) * 100);
|
|
481
|
+
const progressBar = '█'.repeat(Math.floor(percentage / 5)) + '░'.repeat(20 - Math.floor(percentage / 5));
|
|
482
|
+
|
|
483
|
+
process.stdout.write(`\r${Colors.primary('[')}${Colors.success(progressBar)}${Colors.primary(']')} ${percentage}% ${Colors.muted(operation)}`);
|
|
484
|
+
|
|
485
|
+
if (current === total) {
|
|
486
|
+
process.stdout.write('\n');
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Clear the current line (useful for progress indicators)
|
|
492
|
+
*/
|
|
493
|
+
static clearLine(): void {
|
|
494
|
+
process.stdout.write('\r\x1b[K');
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Show a simple status message with icon
|
|
499
|
+
*/
|
|
500
|
+
static showStatus(type: 'success' | 'error' | 'warning' | 'info', message: string): void {
|
|
501
|
+
const icons = {
|
|
502
|
+
success: '✅',
|
|
503
|
+
error: '❌',
|
|
504
|
+
warning: '⚠️',
|
|
505
|
+
info: 'ℹ️'
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
const colors = {
|
|
509
|
+
success: Colors.success,
|
|
510
|
+
error: Colors.error,
|
|
511
|
+
warning: Colors.warning,
|
|
512
|
+
info: Colors.info
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
console.log(`${icons[type]} ${colors[type](message)}`);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Show a list of items with bullets
|
|
520
|
+
*/
|
|
521
|
+
static showList(items: string[], bullet: string = '•'): void {
|
|
522
|
+
items.forEach(item => {
|
|
523
|
+
console.log(` ${Colors.muted(bullet)} ${item}`);
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Show a key-value pair
|
|
529
|
+
*/
|
|
530
|
+
static showKeyValue(key: string, value: string, indent: number = 0): void {
|
|
531
|
+
const spaces = ' '.repeat(indent);
|
|
532
|
+
console.log(`${spaces}${Colors.muted(key + ':')} ${value}`);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Show JUnit XML report for violations
|
|
537
|
+
*/
|
|
538
|
+
static showJUnitReport(violations: Violation[]): void {
|
|
539
|
+
const testSuites = this.groupViolationsByFile(violations);
|
|
540
|
+
const totalTests = Object.keys(testSuites).length;
|
|
541
|
+
const totalFailures = violations.length;
|
|
542
|
+
|
|
543
|
+
console.log('<?xml version="1.0" encoding="UTF-8"?>');
|
|
544
|
+
console.log(`<testsuites tests="${totalTests}" failures="${totalFailures}" time="0">`);
|
|
545
|
+
|
|
546
|
+
Object.entries(testSuites).forEach(([file, fileViolations]) => {
|
|
547
|
+
console.log(` <testsuite name="${file}" tests="1" failures="${fileViolations.length}" time="0">`);
|
|
548
|
+
|
|
549
|
+
if (fileViolations.length > 0) {
|
|
550
|
+
console.log(` <testcase name="compatibility-check" classname="${file}">`);
|
|
551
|
+
fileViolations.forEach(violation => {
|
|
552
|
+
console.log(` <failure message="${violation.feature} not compatible with ${violation.browser} ${violation.required}">`);
|
|
553
|
+
console.log(` ${violation.reason || 'Compatibility violation detected'}`);
|
|
554
|
+
console.log(` Line: ${violation.line}, Column: ${violation.column}`);
|
|
555
|
+
console.log(' </failure>');
|
|
556
|
+
});
|
|
557
|
+
console.log(' </testcase>');
|
|
558
|
+
} else {
|
|
559
|
+
console.log(` <testcase name="compatibility-check" classname="${file}"/>`);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
console.log(' </testsuite>');
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
console.log('</testsuites>');
|
|
566
|
+
}
|
|
567
|
+
}
|