baseguard 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +627 -627
- 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 +48 -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 +8 -5
- 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.map +1 -1
- package/dist/core/startup-optimizer.js +4 -8
- 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.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 +269 -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 +566 -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 -255
- package/src/core/system-error-handler.ts +755 -756
- 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/tmp-smoke/.baseguard/backups/config-2026-02-19T12-04-11-067Z-auto.json +30 -0
- package/tmp-smoke/src/bad.css +3 -0
- 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
|
@@ -5,13 +5,13 @@ import chalk from 'chalk';
|
|
|
5
5
|
export function showTerminalHeader() {
|
|
6
6
|
console.clear();
|
|
7
7
|
// Well-spaced ASCII art for "Baseguard" - monochrome for good contrast
|
|
8
|
-
const logo = `
|
|
9
|
-
██████╗ █████╗ ███████╗ ███████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗
|
|
10
|
-
██╔══██╗ ██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ██║ ██║ ██╔══██╗ ██╔══██╗ ██╔══██╗
|
|
11
|
-
██████╔╝ ███████║ ███████╗ █████╗ ██║ ███╗ ██║ ██║ ███████║ ██████╔╝ ██║ ██║
|
|
12
|
-
██╔══██╗ ██╔══██║ ╚════██║ ██╔══╝ ██║ ██║ ██║ ██║ ██╔══██║ ██╔══██╗ ██║ ██║
|
|
13
|
-
██████╔╝ ██║ ██║ ███████║ ███████╗ ╚██████╔╝ ╚██████╔╝ ██║ ██║ ██║ ██║ ██████╔╝
|
|
14
|
-
╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
|
|
8
|
+
const logo = `
|
|
9
|
+
██████╗ █████╗ ███████╗ ███████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗
|
|
10
|
+
██╔══██╗ ██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ██║ ██║ ██╔══██╗ ██╔══██╗ ██╔══██╗
|
|
11
|
+
██████╔╝ ███████║ ███████╗ █████╗ ██║ ███╗ ██║ ██║ ███████║ ██████╔╝ ██║ ██║
|
|
12
|
+
██╔══██╗ ██╔══██║ ╚════██║ ██╔══╝ ██║ ██║ ██║ ██║ ██╔══██║ ██╔══██╗ ██║ ██║
|
|
13
|
+
██████╔╝ ██║ ██║ ███████║ ███████╗ ╚██████╔╝ ╚██████╔╝ ██║ ██║ ██║ ██║ ██████╔╝
|
|
14
|
+
╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
|
|
15
15
|
`;
|
|
16
16
|
// Use a single color that contrasts well with both light and dark terminals
|
|
17
17
|
console.log(chalk.bold.white(logo));
|
|
@@ -31,13 +31,13 @@ export function showCompactHeader() {
|
|
|
31
31
|
*/
|
|
32
32
|
export function showSimpleHeader() {
|
|
33
33
|
console.clear();
|
|
34
|
-
const logo = `
|
|
35
|
-
██████╗ █████╗ ███████╗ ███████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗
|
|
36
|
-
██╔══██╗ ██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ██║ ██║ ██╔══██╗ ██╔══██╗ ██╔══██╗
|
|
37
|
-
██████╔╝ ███████║ ███████╗ █████╗ ██║ ███╗ ██║ ██║ ███████║ ██████╔╝ ██║ ██║
|
|
38
|
-
██╔══██╗ ██╔══██║ ╚════██║ ██╔══╝ ██║ ██║ ██║ ██║ ██╔══██║ ██╔══██╗ ██║ ██║
|
|
39
|
-
██████╔╝ ██║ ██║ ███████║ ███████╗ ╚██████╔╝ ╚██████╔╝ ██║ ██║ ██║ ██║ ██████╔╝
|
|
40
|
-
╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
|
|
34
|
+
const logo = `
|
|
35
|
+
██████╗ █████╗ ███████╗ ███████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗
|
|
36
|
+
██╔══██╗ ██╔══██╗ ██╔════╝ ██╔════╝ ██╔════╝ ██║ ██║ ██╔══██╗ ██╔══██╗ ██╔══██╗
|
|
37
|
+
██████╔╝ ███████║ ███████╗ █████╗ ██║ ███╗ ██║ ██║ ███████║ ██████╔╝ ██║ ██║
|
|
38
|
+
██╔══██╗ ██╔══██║ ╚════██║ ██╔══╝ ██║ ██║ ██║ ██║ ██╔══██║ ██╔══██╗ ██║ ██║
|
|
39
|
+
██████╔╝ ██║ ██║ ███████║ ███████╗ ╚██████╔╝ ╚██████╔╝ ██║ ██║ ██║ ██║ ██████╔╝
|
|
40
|
+
╚═════╝ ╚═╝ ╚═╝ ╚══════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
|
|
41
41
|
`;
|
|
42
42
|
console.log(chalk.bold.white(logo));
|
|
43
43
|
console.log(chalk.bold.white(' Ship Modern Code') +
|
package/package.json
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "baseguard",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "BaseGuard - Never ship incompatible code again. Intelligent browser compatibility enforcement with AI-powered analysis and autonomous fixing.",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"base": "bin/base.js"
|
|
8
|
-
},
|
|
9
|
-
"type": "module",
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc",
|
|
12
|
-
"dev": "tsc --watch",
|
|
13
|
-
"test": "vitest --run",
|
|
14
|
-
"test:watch": "vitest",
|
|
15
|
-
"test:e2e": "vitest --run tests/e2e/",
|
|
16
|
-
"lint": "eslint src/**/*.ts",
|
|
17
|
-
"lint:fix": "eslint src/**/*.ts --fix",
|
|
18
|
-
"format": "prettier --write src/**/*.ts",
|
|
19
|
-
"format:check": "prettier --check src/**/*.ts",
|
|
20
|
-
"typecheck": "tsc --noEmit",
|
|
21
|
-
"prepare": "husky install",
|
|
22
|
-
"prepublishOnly": "npm run build && npm run test",
|
|
23
|
-
"release": "npm version patch && npm publish",
|
|
24
|
-
"clean": "rm -rf dist"
|
|
25
|
-
},
|
|
26
|
-
"keywords": [
|
|
27
|
-
"browser-compatibility",
|
|
28
|
-
"baseline",
|
|
29
|
-
"web-standards",
|
|
30
|
-
"cli",
|
|
31
|
-
"ai",
|
|
32
|
-
"automation",
|
|
33
|
-
"git-hooks",
|
|
34
|
-
"compatibility-checker",
|
|
35
|
-
"web-features",
|
|
36
|
-
"progressive-enhancement",
|
|
37
|
-
"polyfills",
|
|
38
|
-
"gemini",
|
|
39
|
-
"jules",
|
|
40
|
-
"code-fixing",
|
|
41
|
-
"linting",
|
|
42
|
-
"static-analysis",
|
|
43
|
-
"developer-tools",
|
|
44
|
-
"frontend",
|
|
45
|
-
"javascript",
|
|
46
|
-
"css",
|
|
47
|
-
"html",
|
|
48
|
-
"react",
|
|
49
|
-
"vue",
|
|
50
|
-
"svelte"
|
|
51
|
-
],
|
|
52
|
-
"author": "BaseGuard Team",
|
|
53
|
-
"license": "MIT",
|
|
54
|
-
"dependencies": {
|
|
55
|
-
"@babel/parser": "^7.23.6",
|
|
56
|
-
"@babel/traverse": "^7.23.6",
|
|
57
|
-
"@babel/types": "^7.23.6",
|
|
58
|
-
"@vue/compiler-sfc": "^3.3.13",
|
|
59
|
-
"boxen": "^7.1.1",
|
|
60
|
-
"chalk": "^5.3.0",
|
|
61
|
-
"cli-table3": "^0.6.3",
|
|
62
|
-
"commander": "^11.1.0",
|
|
63
|
-
"figlet": "^1.9.3",
|
|
64
|
-
"glob": "^10.3.10",
|
|
65
|
-
"gradient-string": "^2.0.2",
|
|
66
|
-
"husky": "^8.0.3",
|
|
67
|
-
"inquirer": "^9.2.12",
|
|
68
|
-
"node-fetch": "^3.3.2",
|
|
69
|
-
"open": "^9.1.0",
|
|
70
|
-
"ora": "^7.0.1",
|
|
71
|
-
"postcss": "^8.4.32",
|
|
72
|
-
"postcss-selector-parser": "^6.0.13",
|
|
73
|
-
"svelte": "^4.2.8",
|
|
74
|
-
"web-features": "^0.8.4"
|
|
75
|
-
},
|
|
76
|
-
"devDependencies": {
|
|
77
|
-
"@types/babel__traverse": "^7.28.0",
|
|
78
|
-
"@types/figlet": "^1.7.0",
|
|
79
|
-
"@types/glob": "^8.1.0",
|
|
80
|
-
"@types/gradient-string": "^1.1.6",
|
|
81
|
-
"@types/inquirer": "^9.0.7",
|
|
82
|
-
"@types/node": "^20.10.5",
|
|
83
|
-
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
84
|
-
"@typescript-eslint/parser": "^6.21.0",
|
|
85
|
-
"eslint": "^8.56.0",
|
|
86
|
-
"prettier": "^3.1.1",
|
|
87
|
-
"typescript": "^5.3.3",
|
|
88
|
-
"vitest": "^1.1.0"
|
|
89
|
-
},
|
|
90
|
-
"engines": {
|
|
91
|
-
"node": ">=18.0.0"
|
|
92
|
-
},
|
|
93
|
-
"directories": {
|
|
94
|
-
"test": "tests"
|
|
95
|
-
},
|
|
96
|
-
"repository": {
|
|
97
|
-
"type": "git",
|
|
98
|
-
"url": "git+https://github.com/ebuka1017/baseguard.git"
|
|
99
|
-
},
|
|
100
|
-
"types": "./dist/index.d.ts",
|
|
101
|
-
"bugs": {
|
|
102
|
-
"url": "https://github.com/ebuka1017/baseguard/issues"
|
|
103
|
-
},
|
|
104
|
-
"homepage": "https://github.com/ebuka1017/baseguard#readme"
|
|
105
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "baseguard",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "BaseGuard - Never ship incompatible code again. Intelligent browser compatibility enforcement with AI-powered analysis and autonomous fixing.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"base": "bin/base.js"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"test": "vitest --run",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"test:e2e": "vitest --run tests/e2e/",
|
|
16
|
+
"lint": "eslint src/**/*.ts",
|
|
17
|
+
"lint:fix": "eslint src/**/*.ts --fix",
|
|
18
|
+
"format": "prettier --write src/**/*.ts",
|
|
19
|
+
"format:check": "prettier --check src/**/*.ts",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"prepare": "husky install",
|
|
22
|
+
"prepublishOnly": "npm run build && npm run test",
|
|
23
|
+
"release": "npm version patch && npm publish",
|
|
24
|
+
"clean": "rm -rf dist"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"browser-compatibility",
|
|
28
|
+
"baseline",
|
|
29
|
+
"web-standards",
|
|
30
|
+
"cli",
|
|
31
|
+
"ai",
|
|
32
|
+
"automation",
|
|
33
|
+
"git-hooks",
|
|
34
|
+
"compatibility-checker",
|
|
35
|
+
"web-features",
|
|
36
|
+
"progressive-enhancement",
|
|
37
|
+
"polyfills",
|
|
38
|
+
"gemini",
|
|
39
|
+
"jules",
|
|
40
|
+
"code-fixing",
|
|
41
|
+
"linting",
|
|
42
|
+
"static-analysis",
|
|
43
|
+
"developer-tools",
|
|
44
|
+
"frontend",
|
|
45
|
+
"javascript",
|
|
46
|
+
"css",
|
|
47
|
+
"html",
|
|
48
|
+
"react",
|
|
49
|
+
"vue",
|
|
50
|
+
"svelte"
|
|
51
|
+
],
|
|
52
|
+
"author": "BaseGuard Team",
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@babel/parser": "^7.23.6",
|
|
56
|
+
"@babel/traverse": "^7.23.6",
|
|
57
|
+
"@babel/types": "^7.23.6",
|
|
58
|
+
"@vue/compiler-sfc": "^3.3.13",
|
|
59
|
+
"boxen": "^7.1.1",
|
|
60
|
+
"chalk": "^5.3.0",
|
|
61
|
+
"cli-table3": "^0.6.3",
|
|
62
|
+
"commander": "^11.1.0",
|
|
63
|
+
"figlet": "^1.9.3",
|
|
64
|
+
"glob": "^10.3.10",
|
|
65
|
+
"gradient-string": "^2.0.2",
|
|
66
|
+
"husky": "^8.0.3",
|
|
67
|
+
"inquirer": "^9.2.12",
|
|
68
|
+
"node-fetch": "^3.3.2",
|
|
69
|
+
"open": "^9.1.0",
|
|
70
|
+
"ora": "^7.0.1",
|
|
71
|
+
"postcss": "^8.4.32",
|
|
72
|
+
"postcss-selector-parser": "^6.0.13",
|
|
73
|
+
"svelte": "^4.2.8",
|
|
74
|
+
"web-features": "^0.8.4"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@types/babel__traverse": "^7.28.0",
|
|
78
|
+
"@types/figlet": "^1.7.0",
|
|
79
|
+
"@types/glob": "^8.1.0",
|
|
80
|
+
"@types/gradient-string": "^1.1.6",
|
|
81
|
+
"@types/inquirer": "^9.0.7",
|
|
82
|
+
"@types/node": "^20.10.5",
|
|
83
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
84
|
+
"@typescript-eslint/parser": "^6.21.0",
|
|
85
|
+
"eslint": "^8.56.0",
|
|
86
|
+
"prettier": "^3.1.1",
|
|
87
|
+
"typescript": "^5.3.3",
|
|
88
|
+
"vitest": "^1.1.0"
|
|
89
|
+
},
|
|
90
|
+
"engines": {
|
|
91
|
+
"node": ">=18.0.0"
|
|
92
|
+
},
|
|
93
|
+
"directories": {
|
|
94
|
+
"test": "tests"
|
|
95
|
+
},
|
|
96
|
+
"repository": {
|
|
97
|
+
"type": "git",
|
|
98
|
+
"url": "git+https://github.com/ebuka1017/baseguard.git"
|
|
99
|
+
},
|
|
100
|
+
"types": "./dist/index.d.ts",
|
|
101
|
+
"bugs": {
|
|
102
|
+
"url": "https://github.com/ebuka1017/baseguard/issues"
|
|
103
|
+
},
|
|
104
|
+
"homepage": "https://github.com/ebuka1017/baseguard#readme"
|
|
105
|
+
}
|
|
@@ -1,181 +1,181 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { GeminiAnalyzer } from '../gemini-analyzer.js';
|
|
3
|
-
import type { Violation } from '../../types/index.js';
|
|
4
|
-
|
|
5
|
-
// Mock fetch globally
|
|
6
|
-
global.fetch = vi.fn();
|
|
7
|
-
|
|
8
|
-
describe('GeminiAnalyzer', () => {
|
|
9
|
-
let analyzer: GeminiAnalyzer;
|
|
10
|
-
const mockApiKey = 'AIzaSyDummyKeyForTesting1234567890123456789';
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
analyzer = new GeminiAnalyzer(mockApiKey);
|
|
14
|
-
vi.clearAllMocks();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const mockViolation: Violation = {
|
|
18
|
-
feature: 'container-type',
|
|
19
|
-
featureId: 'container-queries',
|
|
20
|
-
file: 'src/Card.css',
|
|
21
|
-
line: 15,
|
|
22
|
-
column: 5,
|
|
23
|
-
context: ' container-type: inline-size;',
|
|
24
|
-
browser: 'safari',
|
|
25
|
-
required: '15',
|
|
26
|
-
actual: false,
|
|
27
|
-
baselineStatus: 'newly',
|
|
28
|
-
reason: 'Not supported in Safari 15'
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
describe('API Key Validation', () => {
|
|
32
|
-
it('should validate correct API key format', () => {
|
|
33
|
-
expect(GeminiAnalyzer.validateApiKey(mockApiKey)).toBe(true);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('should reject invalid API key format', () => {
|
|
37
|
-
expect(GeminiAnalyzer.validateApiKey('invalid-key')).toBe(false);
|
|
38
|
-
expect(GeminiAnalyzer.validateApiKey('AIza123')).toBe(false); // too short
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe('Cache Management', () => {
|
|
43
|
-
it('should cache analysis results', async () => {
|
|
44
|
-
const mockResponse = {
|
|
45
|
-
ok: true,
|
|
46
|
-
json: () => Promise.resolve({
|
|
47
|
-
candidates: [{
|
|
48
|
-
content: {
|
|
49
|
-
parts: [{ text: 'Test analysis response with 5% market share impact.' }]
|
|
50
|
-
},
|
|
51
|
-
groundingMetadata: {
|
|
52
|
-
groundingChunks: [
|
|
53
|
-
{ web: { uri: 'https://web.dev/container-queries' } }
|
|
54
|
-
]
|
|
55
|
-
}
|
|
56
|
-
}]
|
|
57
|
-
})
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
61
|
-
|
|
62
|
-
// First call should hit the API
|
|
63
|
-
const analysis1 = await analyzer.analyzeViolation(mockViolation);
|
|
64
|
-
expect(fetch).toHaveBeenCalledTimes(1);
|
|
65
|
-
|
|
66
|
-
// Second call should use cache
|
|
67
|
-
const analysis2 = await analyzer.analyzeViolation(mockViolation);
|
|
68
|
-
expect(fetch).toHaveBeenCalledTimes(1); // Still only 1 call
|
|
69
|
-
|
|
70
|
-
expect(analysis1.violation.feature).toBe(analysis2.violation.feature);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should clear cache when requested', async () => {
|
|
74
|
-
analyzer.clearCache();
|
|
75
|
-
const stats = analyzer.getCacheStats();
|
|
76
|
-
expect(stats.size).toBe(0);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
describe('Error Handling', () => {
|
|
81
|
-
it('should handle API errors gracefully', async () => {
|
|
82
|
-
(global.fetch as any).mockRejectedValue(new Error('Network error'));
|
|
83
|
-
|
|
84
|
-
const analysis = await analyzer.analyzeViolation(mockViolation);
|
|
85
|
-
|
|
86
|
-
expect(analysis.confidence).toBe(0.3); // Fallback confidence
|
|
87
|
-
expect(analysis.plainEnglish).toContain('Analysis unavailable');
|
|
88
|
-
expect(analysis.fixStrategy).toBe('progressive enhancement');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should handle invalid API responses', async () => {
|
|
92
|
-
const mockResponse = {
|
|
93
|
-
ok: true,
|
|
94
|
-
json: () => Promise.resolve({ candidates: [] })
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
98
|
-
|
|
99
|
-
const analysis = await analyzer.analyzeViolation(mockViolation);
|
|
100
|
-
|
|
101
|
-
expect(analysis.confidence).toBe(0.3);
|
|
102
|
-
expect(analysis.plainEnglish).toContain('Analysis unavailable');
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
describe('Response Parsing', () => {
|
|
107
|
-
it('should extract market share from response', async () => {
|
|
108
|
-
const mockResponse = {
|
|
109
|
-
ok: true,
|
|
110
|
-
json: () => Promise.resolve({
|
|
111
|
-
candidates: [{
|
|
112
|
-
content: {
|
|
113
|
-
parts: [{ text: 'This affects approximately 8.5% of users on Safari 15.' }]
|
|
114
|
-
},
|
|
115
|
-
groundingMetadata: {
|
|
116
|
-
groundingChunks: [
|
|
117
|
-
{ web: { uri: 'https://caniuse.com/css-container-queries' } }
|
|
118
|
-
]
|
|
119
|
-
}
|
|
120
|
-
}]
|
|
121
|
-
})
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
125
|
-
|
|
126
|
-
const analysis = await analyzer.analyzeViolation(mockViolation);
|
|
127
|
-
|
|
128
|
-
expect(analysis.marketShare).toBe(0.085);
|
|
129
|
-
expect(analysis.sources).toContain('https://caniuse.com/css-container-queries');
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('should extract best practices from response', async () => {
|
|
133
|
-
const mockResponse = {
|
|
134
|
-
ok: true,
|
|
135
|
-
json: () => Promise.resolve({
|
|
136
|
-
candidates: [{
|
|
137
|
-
content: {
|
|
138
|
-
parts: [{
|
|
139
|
-
text: 'Use @supports for feature detection. Consider using polyfills. Test across target browsers.'
|
|
140
|
-
}]
|
|
141
|
-
},
|
|
142
|
-
groundingMetadata: { groundingChunks: [] }
|
|
143
|
-
}]
|
|
144
|
-
})
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
148
|
-
|
|
149
|
-
const analysis = await analyzer.analyzeViolation(mockViolation);
|
|
150
|
-
|
|
151
|
-
expect(analysis.bestPractices).toContain('Use @supports for feature detection');
|
|
152
|
-
expect(analysis.bestPractices).toContain('Consider using polyfills');
|
|
153
|
-
expect(analysis.bestPractices).toContain('Test across target browsers');
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
describe('Batch Processing', () => {
|
|
158
|
-
it('should process multiple violations with concurrency control', async () => {
|
|
159
|
-
const mockResponse = {
|
|
160
|
-
ok: true,
|
|
161
|
-
json: () => Promise.resolve({
|
|
162
|
-
candidates: [{
|
|
163
|
-
content: {
|
|
164
|
-
parts: [{ text: 'Test analysis response.' }]
|
|
165
|
-
},
|
|
166
|
-
groundingMetadata: { groundingChunks: [] }
|
|
167
|
-
}]
|
|
168
|
-
})
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
172
|
-
|
|
173
|
-
const violations = [mockViolation, { ...mockViolation, feature: 'dialog' }];
|
|
174
|
-
const analyses = await analyzer.analyzeViolations(violations, 2);
|
|
175
|
-
|
|
176
|
-
expect(analyses).toHaveLength(2);
|
|
177
|
-
expect(analyses[0].violation.feature).toBe('container-type');
|
|
178
|
-
expect(analyses[1].violation.feature).toBe('dialog');
|
|
179
|
-
});
|
|
180
|
-
});
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { GeminiAnalyzer } from '../gemini-analyzer.js';
|
|
3
|
+
import type { Violation } from '../../types/index.js';
|
|
4
|
+
|
|
5
|
+
// Mock fetch globally
|
|
6
|
+
global.fetch = vi.fn();
|
|
7
|
+
|
|
8
|
+
describe('GeminiAnalyzer', () => {
|
|
9
|
+
let analyzer: GeminiAnalyzer;
|
|
10
|
+
const mockApiKey = 'AIzaSyDummyKeyForTesting1234567890123456789';
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
analyzer = new GeminiAnalyzer(mockApiKey);
|
|
14
|
+
vi.clearAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const mockViolation: Violation = {
|
|
18
|
+
feature: 'container-type',
|
|
19
|
+
featureId: 'container-queries',
|
|
20
|
+
file: 'src/Card.css',
|
|
21
|
+
line: 15,
|
|
22
|
+
column: 5,
|
|
23
|
+
context: ' container-type: inline-size;',
|
|
24
|
+
browser: 'safari',
|
|
25
|
+
required: '15',
|
|
26
|
+
actual: false,
|
|
27
|
+
baselineStatus: 'newly',
|
|
28
|
+
reason: 'Not supported in Safari 15'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
describe('API Key Validation', () => {
|
|
32
|
+
it('should validate correct API key format', () => {
|
|
33
|
+
expect(GeminiAnalyzer.validateApiKey(mockApiKey)).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should reject invalid API key format', () => {
|
|
37
|
+
expect(GeminiAnalyzer.validateApiKey('invalid-key')).toBe(false);
|
|
38
|
+
expect(GeminiAnalyzer.validateApiKey('AIza123')).toBe(false); // too short
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('Cache Management', () => {
|
|
43
|
+
it('should cache analysis results', async () => {
|
|
44
|
+
const mockResponse = {
|
|
45
|
+
ok: true,
|
|
46
|
+
json: () => Promise.resolve({
|
|
47
|
+
candidates: [{
|
|
48
|
+
content: {
|
|
49
|
+
parts: [{ text: 'Test analysis response with 5% market share impact.' }]
|
|
50
|
+
},
|
|
51
|
+
groundingMetadata: {
|
|
52
|
+
groundingChunks: [
|
|
53
|
+
{ web: { uri: 'https://web.dev/container-queries' } }
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}]
|
|
57
|
+
})
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
61
|
+
|
|
62
|
+
// First call should hit the API
|
|
63
|
+
const analysis1 = await analyzer.analyzeViolation(mockViolation);
|
|
64
|
+
expect(fetch).toHaveBeenCalledTimes(1);
|
|
65
|
+
|
|
66
|
+
// Second call should use cache
|
|
67
|
+
const analysis2 = await analyzer.analyzeViolation(mockViolation);
|
|
68
|
+
expect(fetch).toHaveBeenCalledTimes(1); // Still only 1 call
|
|
69
|
+
|
|
70
|
+
expect(analysis1.violation.feature).toBe(analysis2.violation.feature);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should clear cache when requested', async () => {
|
|
74
|
+
analyzer.clearCache();
|
|
75
|
+
const stats = analyzer.getCacheStats();
|
|
76
|
+
expect(stats.size).toBe(0);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('Error Handling', () => {
|
|
81
|
+
it('should handle API errors gracefully', async () => {
|
|
82
|
+
(global.fetch as any).mockRejectedValue(new Error('Network error'));
|
|
83
|
+
|
|
84
|
+
const analysis = await analyzer.analyzeViolation(mockViolation);
|
|
85
|
+
|
|
86
|
+
expect(analysis.confidence).toBe(0.3); // Fallback confidence
|
|
87
|
+
expect(analysis.plainEnglish).toContain('Analysis unavailable');
|
|
88
|
+
expect(analysis.fixStrategy).toBe('progressive enhancement');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should handle invalid API responses', async () => {
|
|
92
|
+
const mockResponse = {
|
|
93
|
+
ok: true,
|
|
94
|
+
json: () => Promise.resolve({ candidates: [] })
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
98
|
+
|
|
99
|
+
const analysis = await analyzer.analyzeViolation(mockViolation);
|
|
100
|
+
|
|
101
|
+
expect(analysis.confidence).toBe(0.3);
|
|
102
|
+
expect(analysis.plainEnglish).toContain('Analysis unavailable');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('Response Parsing', () => {
|
|
107
|
+
it('should extract market share from response', async () => {
|
|
108
|
+
const mockResponse = {
|
|
109
|
+
ok: true,
|
|
110
|
+
json: () => Promise.resolve({
|
|
111
|
+
candidates: [{
|
|
112
|
+
content: {
|
|
113
|
+
parts: [{ text: 'This affects approximately 8.5% of users on Safari 15.' }]
|
|
114
|
+
},
|
|
115
|
+
groundingMetadata: {
|
|
116
|
+
groundingChunks: [
|
|
117
|
+
{ web: { uri: 'https://caniuse.com/css-container-queries' } }
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}]
|
|
121
|
+
})
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
125
|
+
|
|
126
|
+
const analysis = await analyzer.analyzeViolation(mockViolation);
|
|
127
|
+
|
|
128
|
+
expect(analysis.marketShare).toBe(0.085);
|
|
129
|
+
expect(analysis.sources).toContain('https://caniuse.com/css-container-queries');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should extract best practices from response', async () => {
|
|
133
|
+
const mockResponse = {
|
|
134
|
+
ok: true,
|
|
135
|
+
json: () => Promise.resolve({
|
|
136
|
+
candidates: [{
|
|
137
|
+
content: {
|
|
138
|
+
parts: [{
|
|
139
|
+
text: 'Use @supports for feature detection. Consider using polyfills. Test across target browsers.'
|
|
140
|
+
}]
|
|
141
|
+
},
|
|
142
|
+
groundingMetadata: { groundingChunks: [] }
|
|
143
|
+
}]
|
|
144
|
+
})
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
148
|
+
|
|
149
|
+
const analysis = await analyzer.analyzeViolation(mockViolation);
|
|
150
|
+
|
|
151
|
+
expect(analysis.bestPractices).toContain('Use @supports for feature detection');
|
|
152
|
+
expect(analysis.bestPractices).toContain('Consider using polyfills');
|
|
153
|
+
expect(analysis.bestPractices).toContain('Test across target browsers');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('Batch Processing', () => {
|
|
158
|
+
it('should process multiple violations with concurrency control', async () => {
|
|
159
|
+
const mockResponse = {
|
|
160
|
+
ok: true,
|
|
161
|
+
json: () => Promise.resolve({
|
|
162
|
+
candidates: [{
|
|
163
|
+
content: {
|
|
164
|
+
parts: [{ text: 'Test analysis response.' }]
|
|
165
|
+
},
|
|
166
|
+
groundingMetadata: { groundingChunks: [] }
|
|
167
|
+
}]
|
|
168
|
+
})
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
(global.fetch as any).mockResolvedValue(mockResponse);
|
|
172
|
+
|
|
173
|
+
const violations = [mockViolation, { ...mockViolation, feature: 'dialog' }];
|
|
174
|
+
const analyses = await analyzer.analyzeViolations(violations, 2);
|
|
175
|
+
|
|
176
|
+
expect(analyses).toHaveLength(2);
|
|
177
|
+
expect(analyses[0].violation.feature).toBe('container-type');
|
|
178
|
+
expect(analyses[1].violation.feature).toBe('dialog');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
181
|
});
|