@gemini-designer/mcp-server 0.1.2 → 0.1.29
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/dist/components/catalog.d.ts.map +1 -1
- package/dist/components/catalog.js +10 -4
- package/dist/components/catalog.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +11 -6
- package/dist/config/index.js.map +1 -1
- package/dist/context/builder.d.ts.map +1 -1
- package/dist/context/builder.js.map +1 -1
- package/dist/context/filter.d.ts.map +1 -1
- package/dist/context/filter.js +5 -1
- package/dist/context/filter.js.map +1 -1
- package/dist/context/grounding.d.ts.map +1 -1
- package/dist/context/grounding.js +7 -3
- package/dist/context/grounding.js.map +1 -1
- package/dist/context/guards.d.ts.map +1 -1
- package/dist/context/guards.js +53 -0
- package/dist/context/guards.js.map +1 -1
- package/dist/context/repo-hints.js.map +1 -1
- package/dist/context/styling-detector.d.ts +24 -0
- package/dist/context/styling-detector.d.ts.map +1 -0
- package/dist/context/styling-detector.js +337 -0
- package/dist/context/styling-detector.js.map +1 -0
- package/dist/design/principles.js.map +1 -1
- package/dist/generation/gemini-client.d.ts.map +1 -1
- package/dist/generation/gemini-client.js.map +1 -1
- package/dist/generation/litellm-client.d.ts.map +1 -1
- package/dist/generation/litellm-client.js +14 -7
- package/dist/generation/litellm-client.js.map +1 -1
- package/dist/generation/remote-client.d.ts +10 -5
- package/dist/generation/remote-client.d.ts.map +1 -1
- package/dist/generation/remote-client.js +13 -2
- package/dist/generation/remote-client.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/output/file-writer.d.ts.map +1 -1
- package/dist/output/file-writer.js +4 -4
- package/dist/output/file-writer.js.map +1 -1
- package/dist/output/formatter.d.ts.map +1 -1
- package/dist/output/formatter.js +5 -2
- package/dist/output/formatter.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -1
- package/dist/server.js.map +1 -1
- package/dist/stack/detect.d.ts.map +1 -1
- package/dist/stack/detect.js +42 -9
- package/dist/stack/detect.js.map +1 -1
- package/dist/tokens/sync.d.ts.map +1 -1
- package/dist/tokens/sync.js +22 -5
- package/dist/tokens/sync.js.map +1 -1
- package/dist/tools/analyze-screenshot-ui.d.ts.map +1 -1
- package/dist/tools/analyze-screenshot-ui.js +5 -5
- package/dist/tools/analyze-screenshot-ui.js.map +1 -1
- package/dist/tools/analyze-tokens.d.ts.map +1 -1
- package/dist/tools/analyze-tokens.js +3 -1
- package/dist/tools/analyze-tokens.js.map +1 -1
- package/dist/tools/catalog-components.d.ts.map +1 -1
- package/dist/tools/catalog-components.js +1 -4
- package/dist/tools/catalog-components.js.map +1 -1
- package/dist/tools/create-ui.d.ts +3 -0
- package/dist/tools/create-ui.d.ts.map +1 -1
- package/dist/tools/create-ui.js +203 -75
- package/dist/tools/create-ui.js.map +1 -1
- package/dist/tools/detect-ui-stack.js.map +1 -1
- package/dist/tools/generate-component-variants.d.ts.map +1 -1
- package/dist/tools/generate-component-variants.js +15 -4
- package/dist/tools/generate-component-variants.js.map +1 -1
- package/dist/tools/generate-vibes.d.ts.map +1 -1
- package/dist/tools/generate-vibes.js +7 -3
- package/dist/tools/generate-vibes.js.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/modify-ui.d.ts.map +1 -1
- package/dist/tools/modify-ui.js +7 -2
- package/dist/tools/modify-ui.js.map +1 -1
- package/dist/tools/scaffold-project.d.ts.map +1 -1
- package/dist/tools/scaffold-project.js +3 -1
- package/dist/tools/scaffold-project.js.map +1 -1
- package/dist/tools/snippet-ui.d.ts +3 -1
- package/dist/tools/snippet-ui.d.ts.map +1 -1
- package/dist/tools/snippet-ui.js +219 -88
- package/dist/tools/snippet-ui.js.map +1 -1
- package/dist/tools/sync-design-tokens.d.ts.map +1 -1
- package/dist/tools/sync-design-tokens.js +26 -11
- package/dist/tools/sync-design-tokens.js.map +1 -1
- package/dist/utils/walk.d.ts.map +1 -1
- package/dist/utils/walk.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/package.json +55 -55
- package/src/__tests__/builder.test.ts +19 -19
- package/src/__tests__/config.test.ts +63 -31
- package/src/__tests__/filter.test.ts +98 -92
- package/src/__tests__/remote-client.test.ts +179 -0
- package/src/components/catalog.ts +170 -166
- package/src/config/index.ts +185 -177
- package/src/context/builder.ts +157 -157
- package/src/context/filter.ts +110 -104
- package/src/context/grounding.ts +143 -129
- package/src/context/guards.ts +97 -38
- package/src/context/repo-hints.ts +24 -24
- package/src/context/styling-detector.ts +460 -0
- package/src/design/principles.ts +14 -14
- package/src/generation/gemini-client.ts +53 -56
- package/src/generation/litellm-client.ts +102 -86
- package/src/generation/remote-client.ts +100 -77
- package/src/index.ts +16 -16
- package/src/output/file-writer.ts +123 -123
- package/src/output/formatter.ts +139 -132
- package/src/server.ts +12 -11
- package/src/stack/detect.ts +226 -175
- package/src/tokens/sync.ts +189 -155
- package/src/tools/analyze-screenshot-ui.ts +89 -88
- package/src/tools/analyze-tokens.ts +80 -78
- package/src/tools/catalog-components.ts +68 -68
- package/src/tools/create-ui.ts +295 -142
- package/src/tools/detect-ui-stack.ts +36 -36
- package/src/tools/generate-component-variants.ts +155 -135
- package/src/tools/generate-vibes.ts +121 -117
- package/src/tools/index.ts +14 -14
- package/src/tools/modify-ui.ts +170 -165
- package/src/tools/scaffold-project.ts +68 -66
- package/src/tools/snippet-ui.ts +323 -172
- package/src/tools/sync-design-tokens.ts +217 -195
- package/src/utils/walk.ts +47 -45
- package/src/version.ts +6 -0
- package/tsconfig.json +23 -33
- package/vitest.config.ts +10 -10
- package/.prettierrc +0 -9
- package/eslint.config.js +0 -37
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAyB,CAAC;AAE/D,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
}
|
|
2
|
+
"name": "@gemini-designer/mcp-server",
|
|
3
|
+
"version": "0.1.29",
|
|
4
|
+
"description": "MCP server for AI-powered UI design and code generation with Gemini",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"gemini-designer-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"dev": "tsx watch src/index.ts",
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"test": "vitest run",
|
|
15
|
+
"test:coverage": "vitest run --coverage",
|
|
16
|
+
"lint": "eslint src/",
|
|
17
|
+
"lint:fix": "eslint src/ --fix",
|
|
18
|
+
"format": "prettier --write src/",
|
|
19
|
+
"typecheck": "tsc --noEmit"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mcp",
|
|
23
|
+
"model-context-protocol",
|
|
24
|
+
"gemini",
|
|
25
|
+
"design-to-code",
|
|
26
|
+
"ai",
|
|
27
|
+
"frontend",
|
|
28
|
+
"ui-generation"
|
|
29
|
+
],
|
|
30
|
+
"author": "",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20.0.0"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/yourusername/gemini-designer-mcp"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://gemini-designer.dev",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@google/generative-ai": "^0.21.0",
|
|
42
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
43
|
+
"prettier": "^3.4.0",
|
|
44
|
+
"typescript": "^5.7.0",
|
|
45
|
+
"zod": "^3.24.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^22.10.0",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
50
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
51
|
+
"@vitest/coverage-v8": "^2.1.0",
|
|
52
|
+
"eslint": "^9.16.0",
|
|
53
|
+
"tsx": "^4.19.0",
|
|
54
|
+
"vitest": "^2.1.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -6,26 +6,26 @@ import { describe, it, expect } from 'vitest';
|
|
|
6
6
|
import { estimateTokens } from '../context/builder.js';
|
|
7
7
|
|
|
8
8
|
describe('estimateTokens', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
it('should estimate tokens based on character count', () => {
|
|
10
|
+
// ~4 chars per token
|
|
11
|
+
expect(estimateTokens('hello')).toBe(2); // 5 chars → ~2 tokens
|
|
12
|
+
expect(estimateTokens('')).toBe(0);
|
|
13
|
+
});
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
it('should handle longer text', () => {
|
|
16
|
+
const text = 'a'.repeat(100);
|
|
17
|
+
expect(estimateTokens(text)).toBe(25); // 100 chars → 25 tokens
|
|
18
|
+
});
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
it('should round up for partial tokens', () => {
|
|
21
|
+
const text = 'ab'; // 2 chars → 0.5 → rounds to 1
|
|
22
|
+
expect(estimateTokens(text)).toBe(1);
|
|
23
|
+
});
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
it('should handle code snippets', () => {
|
|
26
|
+
const code = 'const Button = () => <button>Click</button>;';
|
|
27
|
+
const tokens = estimateTokens(code);
|
|
28
|
+
expect(tokens).toBeGreaterThan(0);
|
|
29
|
+
expect(tokens).toBe(Math.ceil(code.length / 4));
|
|
30
|
+
});
|
|
31
31
|
});
|
|
@@ -5,48 +5,80 @@
|
|
|
5
5
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
6
6
|
|
|
7
7
|
describe('Config', () => {
|
|
8
|
-
|
|
8
|
+
const originalEnv = process.env;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.resetModules();
|
|
12
|
+
process.env = { ...originalEnv };
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
process.env = originalEnv;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('loadConfigFromEnv', () => {
|
|
20
|
+
it('loads GEMINI_API_KEY and falls back to gemini provider when LiteLLM is not configured', async () => {
|
|
21
|
+
process.env.GEMINI_API_KEY = 'test-key';
|
|
22
|
+
|
|
23
|
+
// Dynamic import to get fresh module
|
|
24
|
+
const { loadConfig } = await import('../config/index.js');
|
|
25
|
+
|
|
26
|
+
const cfg = loadConfig();
|
|
27
|
+
expect(cfg.mode).toBe('local');
|
|
28
|
+
expect(cfg.apiKey).toBe('test-key');
|
|
29
|
+
expect(cfg.localProvider).toBe('gemini');
|
|
13
30
|
});
|
|
14
31
|
|
|
15
|
-
|
|
16
|
-
|
|
32
|
+
it('falls back to litellm provider when GEMINI_API_KEY is missing but LITELLM_ENDPOINT is configured', async () => {
|
|
33
|
+
process.env.LITELLM_ENDPOINT = 'http://localhost:4000';
|
|
34
|
+
|
|
35
|
+
const { loadConfig } = await import('../config/index.js');
|
|
36
|
+
const cfg = loadConfig();
|
|
37
|
+
expect(cfg.mode).toBe('local');
|
|
38
|
+
expect(cfg.localProvider).toBe('litellm');
|
|
17
39
|
});
|
|
18
40
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
it('throws when remote mode is selected without a remote endpoint', async () => {
|
|
42
|
+
process.env.GEMINI_DESIGNER_MODE = 'remote';
|
|
43
|
+
process.env.GEMINI_DESIGNER_REMOTE_API_KEY = 'gd_test_key';
|
|
44
|
+
|
|
45
|
+
const { loadConfig } = await import('../config/index.js');
|
|
46
|
+
const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
47
|
+
expect(() => loadConfig()).toThrow(/remote endpoint/i);
|
|
48
|
+
spy.mockRestore();
|
|
49
|
+
});
|
|
22
50
|
|
|
23
|
-
|
|
24
|
-
|
|
51
|
+
it('throws when remote endpoint is plain HTTP (non-localhost)', async () => {
|
|
52
|
+
process.env.GEMINI_DESIGNER_MODE = 'remote';
|
|
53
|
+
process.env.GEMINI_DESIGNER_REMOTE_API_KEY = 'gd_test_key';
|
|
54
|
+
process.env.GEMINI_DESIGNER_REMOTE_ENDPOINT = 'http://example.com';
|
|
25
55
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
56
|
+
const { loadConfig } = await import('../config/index.js');
|
|
57
|
+
const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
58
|
+
expect(() => loadConfig()).toThrow(/insecure remote endpoint/i);
|
|
59
|
+
spy.mockRestore();
|
|
60
|
+
});
|
|
29
61
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
62
|
+
it('allows remote endpoint over HTTP for localhost (dev)', async () => {
|
|
63
|
+
process.env.GEMINI_DESIGNER_MODE = 'remote';
|
|
64
|
+
process.env.GEMINI_DESIGNER_REMOTE_API_KEY = 'gd_test_key';
|
|
65
|
+
process.env.GEMINI_DESIGNER_REMOTE_ENDPOINT = 'http://localhost:3000';
|
|
34
66
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
67
|
+
const { loadConfig } = await import('../config/index.js');
|
|
68
|
+
const cfg = loadConfig();
|
|
69
|
+
expect(cfg.mode).toBe('remote');
|
|
70
|
+
expect(cfg.remoteEndpoint).toBe('http://localhost:3000');
|
|
39
71
|
});
|
|
72
|
+
});
|
|
40
73
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
expect(true).toBe(true); // Placeholder for schema validation
|
|
45
|
-
});
|
|
74
|
+
describe('Config defaults', () => {
|
|
75
|
+
it('defaults framework to react and accessibility to wcag-aa', async () => {
|
|
76
|
+
process.env.GEMINI_API_KEY = 'test-key';
|
|
46
77
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
78
|
+
const { loadConfig } = await import('../config/index.js');
|
|
79
|
+
const cfg = loadConfig();
|
|
80
|
+
expect(cfg.defaultFramework).toBe('react');
|
|
81
|
+
expect(cfg.accessibility).toBe('wcag-aa');
|
|
51
82
|
});
|
|
83
|
+
});
|
|
52
84
|
});
|
|
@@ -3,107 +3,113 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { describe, it, expect } from 'vitest';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
isSensitiveFile,
|
|
8
|
+
isPathAllowed,
|
|
9
|
+
isUIRelevant,
|
|
10
|
+
sanitizeContent,
|
|
11
|
+
} from '../context/filter.js';
|
|
7
12
|
|
|
8
13
|
describe('isSensitiveFile', () => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
14
|
+
it('should flag .env files as sensitive', () => {
|
|
15
|
+
expect(isSensitiveFile('.env')).toBe(true);
|
|
16
|
+
expect(isSensitiveFile('.env.local')).toBe(true);
|
|
17
|
+
expect(isSensitiveFile('/path/to/.env.production')).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should flag secret files as sensitive', () => {
|
|
21
|
+
expect(isSensitiveFile('secrets.json')).toBe(true);
|
|
22
|
+
expect(isSensitiveFile('/config/secrets.yaml')).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should flag private keys as sensitive', () => {
|
|
26
|
+
expect(isSensitiveFile('server.key')).toBe(true);
|
|
27
|
+
expect(isSensitiveFile('certificate.pem')).toBe(true);
|
|
28
|
+
expect(isSensitiveFile('id_rsa')).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should flag backend directories as sensitive', () => {
|
|
32
|
+
expect(isSensitiveFile('/src/api/routes.ts')).toBe(true);
|
|
33
|
+
expect(isSensitiveFile('/server/index.ts')).toBe(true);
|
|
34
|
+
expect(isSensitiveFile('/backend/handlers.ts')).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should not flag UI files as sensitive', () => {
|
|
38
|
+
expect(isSensitiveFile('Button.tsx')).toBe(false);
|
|
39
|
+
expect(isSensitiveFile('/components/Card.tsx')).toBe(false);
|
|
40
|
+
expect(isSensitiveFile('styles.css')).toBe(false);
|
|
41
|
+
});
|
|
37
42
|
});
|
|
38
43
|
|
|
39
44
|
describe('isPathAllowed', () => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
45
|
+
it('should allow paths within allowed directories', () => {
|
|
46
|
+
expect(isPathAllowed('/project/src/file.ts', ['/project'])).toBe(true);
|
|
47
|
+
expect(isPathAllowed('/project/components/Button.tsx', ['/project'])).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should reject paths outside allowed directories', () => {
|
|
51
|
+
expect(isPathAllowed('/etc/passwd', ['/project'])).toBe(false);
|
|
52
|
+
expect(isPathAllowed('/home/user/secrets', ['/project'])).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should support multiple allowed paths', () => {
|
|
56
|
+
const allowed = ['/project', '/shared'];
|
|
57
|
+
expect(isPathAllowed('/project/file.ts', allowed)).toBe(true);
|
|
58
|
+
expect(isPathAllowed('/shared/utils.ts', allowed)).toBe(true);
|
|
59
|
+
expect(isPathAllowed('/other/file.ts', allowed)).toBe(false);
|
|
60
|
+
});
|
|
56
61
|
});
|
|
57
62
|
|
|
58
63
|
describe('isUIRelevant', () => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
64
|
+
it('should identify CSS files as UI relevant', () => {
|
|
65
|
+
expect(isUIRelevant('styles.css')).toBe(true);
|
|
66
|
+
expect(isUIRelevant('theme.scss')).toBe(true);
|
|
67
|
+
expect(isUIRelevant('variables.less')).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should identify component files as UI relevant', () => {
|
|
71
|
+
expect(isUIRelevant('Button.tsx')).toBe(true);
|
|
72
|
+
expect(isUIRelevant('Card.jsx')).toBe(true);
|
|
73
|
+
expect(isUIRelevant('Header.vue')).toBe(true);
|
|
74
|
+
expect(isUIRelevant('Nav.svelte')).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should identify design token files as UI relevant', () => {
|
|
78
|
+
expect(isUIRelevant('tokens.json')).toBe(true);
|
|
79
|
+
expect(isUIRelevant('design-tokens.ts')).toBe(true);
|
|
80
|
+
expect(isUIRelevant('theme.ts')).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should not identify backend files as UI relevant', () => {
|
|
84
|
+
expect(isUIRelevant('database.ts')).toBe(false);
|
|
85
|
+
expect(isUIRelevant('server.ts')).toBe(false);
|
|
86
|
+
});
|
|
82
87
|
});
|
|
83
88
|
|
|
84
89
|
describe('sanitizeContent', () => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
90
|
+
it('should redact API key patterns', () => {
|
|
91
|
+
const content = 'const apiKey = "sk-abc123xyz";';
|
|
92
|
+
expect(sanitizeContent(content)).toContain('[REDACTED]');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should redact Bearer tokens', () => {
|
|
96
|
+
const content =
|
|
97
|
+
'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ';
|
|
98
|
+
expect(sanitizeContent(content)).toContain('[REDACTED]');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should redact AWS keys', () => {
|
|
102
|
+
const content = 'aws_access_key = "AKIAIOSFODNN7EXAMPLE"';
|
|
103
|
+
expect(sanitizeContent(content)).toContain('[REDACTED]');
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should redact database connection strings', () => {
|
|
107
|
+
const content = 'DATABASE_URL=postgresql://user:password@localhost:5432/db';
|
|
108
|
+
expect(sanitizeContent(content)).toContain('[REDACTED]');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should preserve non-sensitive content', () => {
|
|
112
|
+
const content = 'const Button = () => <button>Click me</button>;';
|
|
113
|
+
expect(sanitizeContent(content)).toBe(content);
|
|
114
|
+
});
|
|
109
115
|
});
|