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,420 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { execSync, spawn } from 'child_process';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
const TEST_TIMEOUT = 30000;
|
|
12
|
+
const TEMP_DIR = path.join(__dirname, '../temp-platform');
|
|
13
|
+
|
|
14
|
+
// Helper function to run BaseGuard commands
|
|
15
|
+
async function runBaseGuard(args: string[], cwd: string = TEMP_DIR): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
16
|
+
return new Promise((resolve) => {
|
|
17
|
+
const basePath = path.join(__dirname, '../../bin/base.js');
|
|
18
|
+
const child = spawn('node', [basePath, ...args], {
|
|
19
|
+
cwd,
|
|
20
|
+
stdio: 'pipe',
|
|
21
|
+
env: { ...process.env, NODE_ENV: 'test' },
|
|
22
|
+
shell: os.platform() === 'win32' // Use shell on Windows
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
let stdout = '';
|
|
26
|
+
let stderr = '';
|
|
27
|
+
|
|
28
|
+
child.stdout?.on('data', (data) => {
|
|
29
|
+
stdout += data.toString();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
child.stderr?.on('data', (data) => {
|
|
33
|
+
stderr += data.toString();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
child.on('close', (code) => {
|
|
37
|
+
resolve({
|
|
38
|
+
stdout,
|
|
39
|
+
stderr,
|
|
40
|
+
exitCode: code || 0
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
setTimeout(() => {
|
|
45
|
+
child.kill();
|
|
46
|
+
resolve({ stdout, stderr, exitCode: 1 });
|
|
47
|
+
}, TEST_TIMEOUT);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Helper function to create test project
|
|
52
|
+
async function createTestProject(projectName: string): Promise<string> {
|
|
53
|
+
const projectPath = path.join(TEMP_DIR, projectName);
|
|
54
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
55
|
+
|
|
56
|
+
// Create test files with various path separators and line endings
|
|
57
|
+
const jsContent = `// Test file for cross-platform compatibility
|
|
58
|
+
const data = { test: 'value' };
|
|
59
|
+
const cloned = structuredClone(data);
|
|
60
|
+
const observer = new ResizeObserver(() => {});
|
|
61
|
+
console.log('Cross-platform test');`;
|
|
62
|
+
|
|
63
|
+
const cssContent = `.container {
|
|
64
|
+
container-type: inline-size;
|
|
65
|
+
aspect-ratio: 16/9;
|
|
66
|
+
backdrop-filter: blur(10px);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@container (min-width: 400px) {
|
|
70
|
+
.container {
|
|
71
|
+
font-size: 1.2rem;
|
|
72
|
+
}
|
|
73
|
+
}`;
|
|
74
|
+
|
|
75
|
+
// Test different line endings
|
|
76
|
+
const windowsLineEndings = jsContent.replace(/\n/g, '\r\n');
|
|
77
|
+
const unixLineEndings = jsContent.replace(/\r\n/g, '\n');
|
|
78
|
+
|
|
79
|
+
await fs.writeFile(path.join(projectPath, 'test-windows.js'), windowsLineEndings);
|
|
80
|
+
await fs.writeFile(path.join(projectPath, 'test-unix.js'), unixLineEndings);
|
|
81
|
+
await fs.writeFile(path.join(projectPath, 'test.css'), cssContent);
|
|
82
|
+
|
|
83
|
+
// Create configuration
|
|
84
|
+
const config = {
|
|
85
|
+
version: '1.0.0',
|
|
86
|
+
targets: [{ browser: 'safari', minVersion: '15' }],
|
|
87
|
+
apiKeys: { jules: null, gemini: null },
|
|
88
|
+
automation: { enabled: false }
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
await fs.writeFile(path.join(projectPath, '.baseguardrc.json'), JSON.stringify(config, null, 2));
|
|
92
|
+
|
|
93
|
+
return projectPath;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
describe('Cross-Platform Compatibility Tests', () => {
|
|
97
|
+
beforeEach(async () => {
|
|
98
|
+
try {
|
|
99
|
+
await fs.rm(TEMP_DIR, { recursive: true, force: true });
|
|
100
|
+
} catch (error) {
|
|
101
|
+
// Directory might not exist
|
|
102
|
+
}
|
|
103
|
+
await fs.mkdir(TEMP_DIR, { recursive: true });
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
afterEach(async () => {
|
|
107
|
+
try {
|
|
108
|
+
await fs.rm(TEMP_DIR, { recursive: true, force: true });
|
|
109
|
+
} catch (error) {
|
|
110
|
+
// Ignore cleanup errors
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('Platform Detection', () => {
|
|
115
|
+
it('should detect current platform correctly', async () => {
|
|
116
|
+
const projectPath = await createTestProject('platform-detection');
|
|
117
|
+
|
|
118
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
119
|
+
|
|
120
|
+
// Should work regardless of platform
|
|
121
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
122
|
+
expect(result.stdout).toContain('compatibility') || expect(result.stdout).toContain('violations');
|
|
123
|
+
}, TEST_TIMEOUT);
|
|
124
|
+
|
|
125
|
+
it('should handle platform-specific paths correctly', async () => {
|
|
126
|
+
const projectPath = await createTestProject('path-handling');
|
|
127
|
+
|
|
128
|
+
// Create nested directory structure
|
|
129
|
+
const nestedPath = path.join(projectPath, 'src', 'components', 'deep');
|
|
130
|
+
await fs.mkdir(nestedPath, { recursive: true });
|
|
131
|
+
|
|
132
|
+
await fs.writeFile(
|
|
133
|
+
path.join(nestedPath, 'Component.js'),
|
|
134
|
+
'const observer = new ResizeObserver(() => {});'
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
138
|
+
|
|
139
|
+
// Should find files in nested paths on all platforms
|
|
140
|
+
expect(result.stdout).toContain('Component.js') || expect(result.stdout).toContain('ResizeObserver');
|
|
141
|
+
}, TEST_TIMEOUT);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('File System Handling', () => {
|
|
145
|
+
it('should handle different line endings correctly', async () => {
|
|
146
|
+
const projectPath = await createTestProject('line-endings');
|
|
147
|
+
|
|
148
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
149
|
+
|
|
150
|
+
// Should detect violations in both Windows and Unix line ending files
|
|
151
|
+
expect(result.stdout).toContain('structuredClone');
|
|
152
|
+
expect(result.stdout).toContain('ResizeObserver');
|
|
153
|
+
|
|
154
|
+
// Should process both files
|
|
155
|
+
expect(result.stdout).toContain('test-windows.js') || expect(result.stdout).toContain('test-unix.js');
|
|
156
|
+
}, TEST_TIMEOUT);
|
|
157
|
+
|
|
158
|
+
it('should handle case-sensitive file systems', async () => {
|
|
159
|
+
const projectPath = await createTestProject('case-sensitivity');
|
|
160
|
+
|
|
161
|
+
// Create files with different cases
|
|
162
|
+
await fs.writeFile(
|
|
163
|
+
path.join(projectPath, 'Component.JS'), // Uppercase extension
|
|
164
|
+
'const observer = new ResizeObserver(() => {});'
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
await fs.writeFile(
|
|
168
|
+
path.join(projectPath, 'STYLES.CSS'), // Uppercase filename
|
|
169
|
+
'.container { container-type: inline-size; }'
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
173
|
+
|
|
174
|
+
// Should handle files regardless of case
|
|
175
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
176
|
+
}, TEST_TIMEOUT);
|
|
177
|
+
|
|
178
|
+
it('should handle long file paths', async () => {
|
|
179
|
+
const projectPath = await createTestProject('long-paths');
|
|
180
|
+
|
|
181
|
+
// Create a very deep directory structure
|
|
182
|
+
let deepPath = projectPath;
|
|
183
|
+
for (let i = 0; i < 10; i++) {
|
|
184
|
+
deepPath = path.join(deepPath, `very-long-directory-name-${i}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
await fs.mkdir(deepPath, { recursive: true });
|
|
189
|
+
await fs.writeFile(
|
|
190
|
+
path.join(deepPath, 'deep-component.js'),
|
|
191
|
+
'const observer = new ResizeObserver(() => {});'
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
195
|
+
|
|
196
|
+
// Should handle deep paths without issues
|
|
197
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
// Some platforms have path length limits, that's acceptable
|
|
200
|
+
console.log('Platform path length limit reached, skipping test');
|
|
201
|
+
}
|
|
202
|
+
}, TEST_TIMEOUT);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('Process and Shell Handling', () => {
|
|
206
|
+
it('should handle different shell environments', async () => {
|
|
207
|
+
const projectPath = await createTestProject('shell-handling');
|
|
208
|
+
|
|
209
|
+
// Test with different environment variables
|
|
210
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
211
|
+
|
|
212
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
213
|
+
expect(result.stdout.length).toBeGreaterThan(0);
|
|
214
|
+
}, TEST_TIMEOUT);
|
|
215
|
+
|
|
216
|
+
it('should handle process signals correctly', async () => {
|
|
217
|
+
const projectPath = await createTestProject('signal-handling');
|
|
218
|
+
|
|
219
|
+
// Start a BaseGuard process
|
|
220
|
+
const basePath = path.join(__dirname, '../../bin/base.js');
|
|
221
|
+
const child = spawn('node', [basePath, 'check'], {
|
|
222
|
+
cwd: projectPath,
|
|
223
|
+
stdio: 'pipe'
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Give it a moment to start
|
|
227
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
228
|
+
|
|
229
|
+
// Send interrupt signal
|
|
230
|
+
child.kill('SIGINT');
|
|
231
|
+
|
|
232
|
+
// Should handle gracefully
|
|
233
|
+
const exitCode = await new Promise<number>((resolve) => {
|
|
234
|
+
child.on('close', (code) => resolve(code || 0));
|
|
235
|
+
setTimeout(() => resolve(1), 5000); // Timeout
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
expect(exitCode).toBeGreaterThanOrEqual(0);
|
|
239
|
+
}, TEST_TIMEOUT);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
describe('Configuration Handling', () => {
|
|
243
|
+
it('should handle different configuration file encodings', async () => {
|
|
244
|
+
const projectPath = await createTestProject('encoding-test');
|
|
245
|
+
|
|
246
|
+
// Create configuration with different encodings
|
|
247
|
+
const config = {
|
|
248
|
+
version: '1.0.0',
|
|
249
|
+
targets: [{ browser: 'safari', minVersion: '15' }],
|
|
250
|
+
description: 'Test with special characters: áéíóú ñ 中文 🚀'
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
await fs.writeFile(
|
|
254
|
+
path.join(projectPath, '.baseguardrc.json'),
|
|
255
|
+
JSON.stringify(config, null, 2),
|
|
256
|
+
'utf8'
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
260
|
+
|
|
261
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
262
|
+
}, TEST_TIMEOUT);
|
|
263
|
+
|
|
264
|
+
it('should handle missing permissions gracefully', async () => {
|
|
265
|
+
const projectPath = await createTestProject('permissions-test');
|
|
266
|
+
|
|
267
|
+
// Try to create a read-only configuration (platform dependent)
|
|
268
|
+
try {
|
|
269
|
+
const configPath = path.join(projectPath, '.baseguardrc.json');
|
|
270
|
+
await fs.chmod(configPath, 0o444); // Read-only
|
|
271
|
+
|
|
272
|
+
const result = await runBaseGuard(['config', 'list'], projectPath);
|
|
273
|
+
|
|
274
|
+
// Should handle read-only files gracefully
|
|
275
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
276
|
+
|
|
277
|
+
// Restore permissions for cleanup
|
|
278
|
+
await fs.chmod(configPath, 0o644);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
// Some platforms might not support chmod, that's okay
|
|
281
|
+
console.log('Platform does not support chmod, skipping permissions test');
|
|
282
|
+
}
|
|
283
|
+
}, TEST_TIMEOUT);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
describe('Node.js Version Compatibility', () => {
|
|
287
|
+
it('should work with current Node.js version', async () => {
|
|
288
|
+
const projectPath = await createTestProject('node-version');
|
|
289
|
+
|
|
290
|
+
const result = await runBaseGuard(['--version'], projectPath);
|
|
291
|
+
|
|
292
|
+
expect(result.exitCode).toBe(0);
|
|
293
|
+
expect(result.stdout).toMatch(/\d+\.\d+\.\d+/);
|
|
294
|
+
}, TEST_TIMEOUT);
|
|
295
|
+
|
|
296
|
+
it('should handle ES modules correctly', async () => {
|
|
297
|
+
const projectPath = await createTestProject('esm-test');
|
|
298
|
+
|
|
299
|
+
// Create an ES module file
|
|
300
|
+
await fs.writeFile(
|
|
301
|
+
path.join(projectPath, 'module.mjs'),
|
|
302
|
+
`
|
|
303
|
+
import { ResizeObserver } from 'some-module';
|
|
304
|
+
export const observer = new ResizeObserver(() => {});
|
|
305
|
+
export default { structuredClone: globalThis.structuredClone };
|
|
306
|
+
`
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
310
|
+
|
|
311
|
+
// Should parse ES modules correctly
|
|
312
|
+
expect(result.stdout).toContain('ResizeObserver') || expect(result.stdout).toContain('structuredClone');
|
|
313
|
+
}, TEST_TIMEOUT);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe('Memory and Performance', () => {
|
|
317
|
+
it('should handle memory constraints gracefully', async () => {
|
|
318
|
+
const projectPath = await createTestProject('memory-test');
|
|
319
|
+
|
|
320
|
+
// Create many files to test memory usage
|
|
321
|
+
const promises = [];
|
|
322
|
+
for (let i = 0; i < 20; i++) {
|
|
323
|
+
promises.push(
|
|
324
|
+
fs.writeFile(
|
|
325
|
+
path.join(projectPath, `file${i}.js`),
|
|
326
|
+
`
|
|
327
|
+
// File ${i}
|
|
328
|
+
const data${i} = { test: ${i} };
|
|
329
|
+
const cloned${i} = structuredClone(data${i});
|
|
330
|
+
const observer${i} = new ResizeObserver(() => {});
|
|
331
|
+
`.repeat(10) // Make files larger
|
|
332
|
+
)
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
await Promise.all(promises);
|
|
336
|
+
|
|
337
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
338
|
+
|
|
339
|
+
// Should complete without memory issues
|
|
340
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
341
|
+
expect(result.stdout).toContain('structuredClone');
|
|
342
|
+
}, TEST_TIMEOUT);
|
|
343
|
+
|
|
344
|
+
it('should handle concurrent file processing', async () => {
|
|
345
|
+
const projectPath = await createTestProject('concurrent-test');
|
|
346
|
+
|
|
347
|
+
// Create files in different subdirectories
|
|
348
|
+
const dirs = ['src', 'components', 'utils', 'styles'];
|
|
349
|
+
const promises = [];
|
|
350
|
+
|
|
351
|
+
for (const dir of dirs) {
|
|
352
|
+
const dirPath = path.join(projectPath, dir);
|
|
353
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
354
|
+
|
|
355
|
+
for (let i = 0; i < 5; i++) {
|
|
356
|
+
promises.push(
|
|
357
|
+
fs.writeFile(
|
|
358
|
+
path.join(dirPath, `${dir}-file${i}.js`),
|
|
359
|
+
`const observer = new ResizeObserver(() => {}); // ${dir} ${i}`
|
|
360
|
+
)
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
await Promise.all(promises);
|
|
366
|
+
|
|
367
|
+
const startTime = Date.now();
|
|
368
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
369
|
+
const duration = Date.now() - startTime;
|
|
370
|
+
|
|
371
|
+
// Should process files efficiently
|
|
372
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
373
|
+
expect(duration).toBeLessThan(15000); // Should complete within 15 seconds
|
|
374
|
+
expect(result.stdout).toContain('ResizeObserver');
|
|
375
|
+
}, TEST_TIMEOUT);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
describe('Error Handling Across Platforms', () => {
|
|
379
|
+
it('should handle file system errors gracefully', async () => {
|
|
380
|
+
const projectPath = await createTestProject('fs-error-test');
|
|
381
|
+
|
|
382
|
+
// Create a file and then make its directory inaccessible (platform dependent)
|
|
383
|
+
const subDir = path.join(projectPath, 'restricted');
|
|
384
|
+
await fs.mkdir(subDir);
|
|
385
|
+
await fs.writeFile(
|
|
386
|
+
path.join(subDir, 'test.js'),
|
|
387
|
+
'const observer = new ResizeObserver(() => {});'
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
try {
|
|
391
|
+
// Try to make directory inaccessible
|
|
392
|
+
await fs.chmod(subDir, 0o000);
|
|
393
|
+
|
|
394
|
+
const result = await runBaseGuard(['check'], projectPath);
|
|
395
|
+
|
|
396
|
+
// Should handle permission errors gracefully
|
|
397
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
398
|
+
|
|
399
|
+
// Restore permissions for cleanup
|
|
400
|
+
await fs.chmod(subDir, 0o755);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
// Platform might not support chmod
|
|
403
|
+
console.log('Platform does not support chmod, skipping FS error test');
|
|
404
|
+
}
|
|
405
|
+
}, TEST_TIMEOUT);
|
|
406
|
+
|
|
407
|
+
it('should provide platform-appropriate error messages', async () => {
|
|
408
|
+
const projectPath = await createTestProject('error-message-test');
|
|
409
|
+
|
|
410
|
+
// Try to run BaseGuard on a non-existent directory
|
|
411
|
+
const nonExistentPath = path.join(projectPath, 'does-not-exist');
|
|
412
|
+
|
|
413
|
+
const result = await runBaseGuard(['check'], nonExistentPath);
|
|
414
|
+
|
|
415
|
+
// Should provide helpful error message
|
|
416
|
+
expect(result.exitCode).toBe(1);
|
|
417
|
+
expect(result.stderr).toContain('directory') || expect(result.stderr).toContain('path');
|
|
418
|
+
}, TEST_TIMEOUT);
|
|
419
|
+
});
|
|
420
|
+
});
|