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.
Files changed (244) hide show
  1. package/.eslintrc.json +25 -0
  2. package/.prettierrc +8 -0
  3. package/README.md +94 -0
  4. package/bin/base.js +494 -0
  5. package/dist/ai/fix-manager.d.ts +67 -0
  6. package/dist/ai/fix-manager.d.ts.map +1 -0
  7. package/dist/ai/fix-manager.js +326 -0
  8. package/dist/ai/fix-manager.js.map +1 -0
  9. package/dist/ai/gemini-analyzer.d.ts +116 -0
  10. package/dist/ai/gemini-analyzer.d.ts.map +1 -0
  11. package/dist/ai/gemini-analyzer.js +572 -0
  12. package/dist/ai/gemini-analyzer.js.map +1 -0
  13. package/dist/ai/index.d.ts +4 -0
  14. package/dist/ai/index.d.ts.map +1 -0
  15. package/dist/ai/index.js +5 -0
  16. package/dist/ai/index.js.map +1 -0
  17. package/dist/ai/jules-implementer.d.ts +115 -0
  18. package/dist/ai/jules-implementer.d.ts.map +1 -0
  19. package/dist/ai/jules-implementer.js +387 -0
  20. package/dist/ai/jules-implementer.js.map +1 -0
  21. package/dist/commands/automation.d.ts +5 -0
  22. package/dist/commands/automation.d.ts.map +1 -0
  23. package/dist/commands/automation.js +305 -0
  24. package/dist/commands/automation.js.map +1 -0
  25. package/dist/commands/check.d.ts +9 -0
  26. package/dist/commands/check.d.ts.map +1 -0
  27. package/dist/commands/check.js +113 -0
  28. package/dist/commands/check.js.map +1 -0
  29. package/dist/commands/config.d.ts +11 -0
  30. package/dist/commands/config.d.ts.map +1 -0
  31. package/dist/commands/config.js +324 -0
  32. package/dist/commands/config.js.map +1 -0
  33. package/dist/commands/fix.d.ts +9 -0
  34. package/dist/commands/fix.d.ts.map +1 -0
  35. package/dist/commands/fix.js +207 -0
  36. package/dist/commands/fix.js.map +1 -0
  37. package/dist/commands/index.d.ts +6 -0
  38. package/dist/commands/index.d.ts.map +1 -0
  39. package/dist/commands/index.js +7 -0
  40. package/dist/commands/index.js.map +1 -0
  41. package/dist/commands/init.d.ts +9 -0
  42. package/dist/commands/init.d.ts.map +1 -0
  43. package/dist/commands/init.js +125 -0
  44. package/dist/commands/init.js.map +1 -0
  45. package/dist/core/api-key-manager.d.ts +83 -0
  46. package/dist/core/api-key-manager.d.ts.map +1 -0
  47. package/dist/core/api-key-manager.js +244 -0
  48. package/dist/core/api-key-manager.js.map +1 -0
  49. package/dist/core/baseguard.d.ts +46 -0
  50. package/dist/core/baseguard.d.ts.map +1 -0
  51. package/dist/core/baseguard.js +132 -0
  52. package/dist/core/baseguard.js.map +1 -0
  53. package/dist/core/baseline-checker.d.ts +63 -0
  54. package/dist/core/baseline-checker.d.ts.map +1 -0
  55. package/dist/core/baseline-checker.js +502 -0
  56. package/dist/core/baseline-checker.js.map +1 -0
  57. package/dist/core/cache-manager.d.ts +88 -0
  58. package/dist/core/cache-manager.d.ts.map +1 -0
  59. package/dist/core/cache-manager.js +213 -0
  60. package/dist/core/cache-manager.js.map +1 -0
  61. package/dist/core/configuration.d.ts +140 -0
  62. package/dist/core/configuration.d.ts.map +1 -0
  63. package/dist/core/configuration.js +474 -0
  64. package/dist/core/configuration.js.map +1 -0
  65. package/dist/core/directory-filter.d.ts +90 -0
  66. package/dist/core/directory-filter.d.ts.map +1 -0
  67. package/dist/core/directory-filter.js +319 -0
  68. package/dist/core/directory-filter.js.map +1 -0
  69. package/dist/core/error-handler.d.ts +110 -0
  70. package/dist/core/error-handler.d.ts.map +1 -0
  71. package/dist/core/error-handler.js +392 -0
  72. package/dist/core/error-handler.js.map +1 -0
  73. package/dist/core/file-processor.d.ts +80 -0
  74. package/dist/core/file-processor.d.ts.map +1 -0
  75. package/dist/core/file-processor.js +259 -0
  76. package/dist/core/file-processor.js.map +1 -0
  77. package/dist/core/gitignore-manager.d.ts +44 -0
  78. package/dist/core/gitignore-manager.d.ts.map +1 -0
  79. package/dist/core/gitignore-manager.js +147 -0
  80. package/dist/core/gitignore-manager.js.map +1 -0
  81. package/dist/core/index.d.ts +13 -0
  82. package/dist/core/index.d.ts.map +1 -0
  83. package/dist/core/index.js +13 -0
  84. package/dist/core/index.js.map +1 -0
  85. package/dist/core/lazy-loader.d.ts +68 -0
  86. package/dist/core/lazy-loader.d.ts.map +1 -0
  87. package/dist/core/lazy-loader.js +260 -0
  88. package/dist/core/lazy-loader.js.map +1 -0
  89. package/dist/core/memory-manager.d.ts +1 -0
  90. package/dist/core/memory-manager.d.ts.map +1 -0
  91. package/dist/core/memory-manager.js +2 -0
  92. package/dist/core/memory-manager.js.map +1 -0
  93. package/dist/core/startup-optimizer.d.ts +45 -0
  94. package/dist/core/startup-optimizer.d.ts.map +1 -0
  95. package/dist/core/startup-optimizer.js +140 -0
  96. package/dist/core/startup-optimizer.js.map +1 -0
  97. package/dist/git/automation-engine.d.ts +58 -0
  98. package/dist/git/automation-engine.d.ts.map +1 -0
  99. package/dist/git/automation-engine.js +318 -0
  100. package/dist/git/automation-engine.js.map +1 -0
  101. package/dist/git/github-manager.d.ts +71 -0
  102. package/dist/git/github-manager.d.ts.map +1 -0
  103. package/dist/git/github-manager.js +226 -0
  104. package/dist/git/github-manager.js.map +1 -0
  105. package/dist/git/hook-manager.d.ts +43 -0
  106. package/dist/git/hook-manager.d.ts.map +1 -0
  107. package/dist/git/hook-manager.js +191 -0
  108. package/dist/git/hook-manager.js.map +1 -0
  109. package/dist/git/index.d.ts +4 -0
  110. package/dist/git/index.d.ts.map +1 -0
  111. package/dist/git/index.js +5 -0
  112. package/dist/git/index.js.map +1 -0
  113. package/dist/index.d.ts +8 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +9 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/parsers/feature-validator.d.ts +60 -0
  118. package/dist/parsers/feature-validator.d.ts.map +1 -0
  119. package/dist/parsers/feature-validator.js +483 -0
  120. package/dist/parsers/feature-validator.js.map +1 -0
  121. package/dist/parsers/index.d.ts +8 -0
  122. package/dist/parsers/index.d.ts.map +1 -0
  123. package/dist/parsers/index.js +9 -0
  124. package/dist/parsers/index.js.map +1 -0
  125. package/dist/parsers/parser-manager.d.ts +103 -0
  126. package/dist/parsers/parser-manager.d.ts.map +1 -0
  127. package/dist/parsers/parser-manager.js +321 -0
  128. package/dist/parsers/parser-manager.js.map +1 -0
  129. package/dist/parsers/parser.d.ts +23 -0
  130. package/dist/parsers/parser.d.ts.map +1 -0
  131. package/dist/parsers/parser.js +6 -0
  132. package/dist/parsers/parser.js.map +1 -0
  133. package/dist/parsers/react-parser.d.ts +22 -0
  134. package/dist/parsers/react-parser.d.ts.map +1 -0
  135. package/dist/parsers/react-parser.js +307 -0
  136. package/dist/parsers/react-parser.js.map +1 -0
  137. package/dist/parsers/svelte-parser.d.ts +33 -0
  138. package/dist/parsers/svelte-parser.d.ts.map +1 -0
  139. package/dist/parsers/svelte-parser.js +408 -0
  140. package/dist/parsers/svelte-parser.js.map +1 -0
  141. package/dist/parsers/vanilla-parser.d.ts +31 -0
  142. package/dist/parsers/vanilla-parser.d.ts.map +1 -0
  143. package/dist/parsers/vanilla-parser.js +590 -0
  144. package/dist/parsers/vanilla-parser.js.map +1 -0
  145. package/dist/parsers/vue-parser.d.ts +9 -0
  146. package/dist/parsers/vue-parser.d.ts.map +1 -0
  147. package/dist/parsers/vue-parser.js +16 -0
  148. package/dist/parsers/vue-parser.js.map +1 -0
  149. package/dist/terminal-header.d.ts +12 -0
  150. package/dist/terminal-header.js +45 -0
  151. package/dist/types/index.d.ts +83 -0
  152. package/dist/types/index.d.ts.map +1 -0
  153. package/dist/types/index.js +5 -0
  154. package/dist/types/index.js.map +1 -0
  155. package/dist/ui/components.d.ts +133 -0
  156. package/dist/ui/components.d.ts.map +1 -0
  157. package/dist/ui/components.js +482 -0
  158. package/dist/ui/components.js.map +1 -0
  159. package/dist/ui/help.d.ts +11 -0
  160. package/dist/ui/help.d.ts.map +1 -0
  161. package/dist/ui/help.js +161 -0
  162. package/dist/ui/help.js.map +1 -0
  163. package/dist/ui/index.d.ts +5 -0
  164. package/dist/ui/index.d.ts.map +1 -0
  165. package/dist/ui/index.js +5 -0
  166. package/dist/ui/index.js.map +1 -0
  167. package/dist/ui/prompts.d.ts +63 -0
  168. package/dist/ui/prompts.d.ts.map +1 -0
  169. package/dist/ui/prompts.js +611 -0
  170. package/dist/ui/prompts.js.map +1 -0
  171. package/dist/ui/terminal-header.d.ts +13 -0
  172. package/dist/ui/terminal-header.d.ts.map +1 -0
  173. package/dist/ui/terminal-header.js +46 -0
  174. package/dist/ui/terminal-header.js.map +1 -0
  175. package/package.json +80 -0
  176. package/src/ai/__tests__/gemini-analyzer.test.ts +181 -0
  177. package/src/ai/fix-manager.ts +362 -0
  178. package/src/ai/gemini-analyzer.ts +671 -0
  179. package/src/ai/index.ts +4 -0
  180. package/src/ai/jules-implementer.ts +459 -0
  181. package/src/commands/automation.ts +344 -0
  182. package/src/commands/check.ts +299 -0
  183. package/src/commands/config.ts +365 -0
  184. package/src/commands/fix.ts +234 -0
  185. package/src/commands/index.ts +6 -0
  186. package/src/commands/init.ts +142 -0
  187. package/src/commands/status.ts +0 -0
  188. package/src/core/api-key-manager.ts +298 -0
  189. package/src/core/baseguard.ts +742 -0
  190. package/src/core/baseline-checker.ts +563 -0
  191. package/src/core/cache-manager.ts +270 -0
  192. package/src/core/configuration-recovery.ts +676 -0
  193. package/src/core/configuration.ts +559 -0
  194. package/src/core/debug-logger.ts +590 -0
  195. package/src/core/directory-filter.ts +421 -0
  196. package/src/core/error-handler.ts +517 -0
  197. package/src/core/file-processor.ts +331 -0
  198. package/src/core/gitignore-manager.ts +169 -0
  199. package/src/core/graceful-degradation-manager.ts +596 -0
  200. package/src/core/index.ts +13 -0
  201. package/src/core/lazy-loader.ts +307 -0
  202. package/src/core/logger.ts +0 -0
  203. package/src/core/memory-manager.ts +294 -0
  204. package/src/core/startup-optimizer.ts +173 -0
  205. package/src/core/system-error-handler.ts +746 -0
  206. package/src/git/automation-engine.ts +361 -0
  207. package/src/git/github-manager.ts +260 -0
  208. package/src/git/hook-manager.ts +210 -0
  209. package/src/git/index.ts +4 -0
  210. package/src/index.ts +8 -0
  211. package/src/parsers/feature-validator.ts +559 -0
  212. package/src/parsers/index.ts +8 -0
  213. package/src/parsers/parser-manager.ts +419 -0
  214. package/src/parsers/parser.ts +26 -0
  215. package/src/parsers/react-parser-optimized.ts +161 -0
  216. package/src/parsers/react-parser.ts +359 -0
  217. package/src/parsers/svelte-parser.ts +506 -0
  218. package/src/parsers/vanilla-parser.ts +682 -0
  219. package/src/parsers/vue-parser.ts +472 -0
  220. package/src/types/index.ts +92 -0
  221. package/src/ui/components.ts +567 -0
  222. package/src/ui/help.ts +193 -0
  223. package/src/ui/index.ts +4 -0
  224. package/src/ui/prompts.ts +688 -0
  225. package/src/ui/terminal-header.ts +59 -0
  226. package/test-config-commands.js +56 -0
  227. package/test-header-simple.js +33 -0
  228. package/test-terminal-header.js +12 -0
  229. package/test-ui.js +29 -0
  230. package/tests/e2e/baseguard.e2e.test.ts +516 -0
  231. package/tests/e2e/cross-platform.e2e.test.ts +420 -0
  232. package/tests/e2e/git-integration.e2e.test.ts +487 -0
  233. package/tests/fixtures/react-project/package.json +14 -0
  234. package/tests/fixtures/react-project/src/App.css +76 -0
  235. package/tests/fixtures/react-project/src/App.tsx +77 -0
  236. package/tests/fixtures/svelte-project/package.json +11 -0
  237. package/tests/fixtures/svelte-project/src/App.svelte +369 -0
  238. package/tests/fixtures/vanilla-project/index.html +76 -0
  239. package/tests/fixtures/vanilla-project/script.js +331 -0
  240. package/tests/fixtures/vanilla-project/styles.css +359 -0
  241. package/tests/fixtures/vue-project/package.json +12 -0
  242. package/tests/fixtures/vue-project/src/App.vue +216 -0
  243. package/tsconfig.json +36 -0
  244. 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
+ });