@oalacea/daemon 0.5.0 → 0.6.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 (222) hide show
  1. package/LICENSE +23 -23
  2. package/README.md +147 -141
  3. package/bin/Dockerfile +75 -74
  4. package/dist/cli/cli.d.ts +42 -0
  5. package/dist/cli/cli.d.ts.map +1 -0
  6. package/dist/cli/cli.js +89 -0
  7. package/dist/cli/cli.js.map +1 -0
  8. package/dist/cli/commands/detect.command.d.ts +39 -0
  9. package/dist/cli/commands/detect.command.d.ts.map +1 -0
  10. package/dist/cli/commands/detect.command.js +111 -0
  11. package/dist/cli/commands/detect.command.js.map +1 -0
  12. package/dist/cli/commands/index.d.ts +14 -0
  13. package/dist/cli/commands/index.d.ts.map +1 -0
  14. package/dist/cli/commands/index.js +11 -0
  15. package/dist/cli/commands/index.js.map +1 -0
  16. package/dist/cli/commands/init.command.d.ts +41 -0
  17. package/dist/cli/commands/init.command.d.ts.map +1 -0
  18. package/dist/cli/commands/init.command.js +111 -0
  19. package/dist/cli/commands/init.command.js.map +1 -0
  20. package/dist/cli/commands/test.command.d.ts +58 -0
  21. package/dist/cli/commands/test.command.d.ts.map +1 -0
  22. package/dist/cli/commands/test.command.js +180 -0
  23. package/dist/cli/commands/test.command.js.map +1 -0
  24. package/dist/cli/index.d.ts +8 -0
  25. package/dist/cli/index.d.ts.map +1 -0
  26. package/dist/cli/index.js +10 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/core/config/daemon.config.d.ts +32 -0
  29. package/dist/core/config/daemon.config.d.ts.map +1 -0
  30. package/dist/core/config/daemon.config.js +83 -0
  31. package/dist/core/config/daemon.config.js.map +1 -0
  32. package/dist/core/config/index.d.ts +5 -0
  33. package/dist/core/config/index.d.ts.map +1 -0
  34. package/dist/core/config/index.js +5 -0
  35. package/dist/core/config/index.js.map +1 -0
  36. package/dist/core/constants.d.ts +36 -0
  37. package/dist/core/constants.d.ts.map +1 -0
  38. package/dist/core/constants.js +56 -0
  39. package/dist/core/constants.js.map +1 -0
  40. package/dist/core/types/common.types.d.ts +250 -0
  41. package/dist/core/types/common.types.d.ts.map +1 -0
  42. package/dist/core/types/common.types.js +7 -0
  43. package/dist/core/types/common.types.js.map +1 -0
  44. package/dist/core/types/detection.types.d.ts +232 -0
  45. package/dist/core/types/detection.types.d.ts.map +1 -0
  46. package/dist/core/types/detection.types.js +22 -0
  47. package/dist/core/types/detection.types.js.map +1 -0
  48. package/dist/core/types/docker.types.d.ts +322 -0
  49. package/dist/core/types/docker.types.d.ts.map +1 -0
  50. package/dist/core/types/docker.types.js +7 -0
  51. package/dist/core/types/docker.types.js.map +1 -0
  52. package/dist/core/types/index.d.ts +11 -0
  53. package/dist/core/types/index.d.ts.map +1 -0
  54. package/dist/core/types/index.js +7 -0
  55. package/dist/core/types/index.js.map +1 -0
  56. package/dist/core/types/project.types.d.ts +74 -0
  57. package/dist/core/types/project.types.d.ts.map +1 -0
  58. package/dist/core/types/project.types.js +7 -0
  59. package/dist/core/types/project.types.js.map +1 -0
  60. package/dist/core/types/shared.types.d.ts +118 -0
  61. package/dist/core/types/shared.types.d.ts.map +1 -0
  62. package/dist/core/types/shared.types.js +7 -0
  63. package/dist/core/types/shared.types.js.map +1 -0
  64. package/dist/core/types/test.types.d.ts +230 -0
  65. package/dist/core/types/test.types.d.ts.map +1 -0
  66. package/dist/core/types/test.types.js +7 -0
  67. package/dist/core/types/test.types.js.map +1 -0
  68. package/dist/services/detection/__tests__/framework-detector.test.d.ts +5 -0
  69. package/dist/services/detection/__tests__/framework-detector.test.d.ts.map +1 -0
  70. package/dist/services/detection/__tests__/framework-detector.test.js +52 -0
  71. package/dist/services/detection/__tests__/framework-detector.test.js.map +1 -0
  72. package/dist/services/detection/framework-detector.d.ts +179 -0
  73. package/dist/services/detection/framework-detector.d.ts.map +1 -0
  74. package/dist/services/detection/framework-detector.js +636 -0
  75. package/dist/services/detection/framework-detector.js.map +1 -0
  76. package/dist/services/detection/index.d.ts +10 -0
  77. package/dist/services/detection/index.d.ts.map +1 -0
  78. package/dist/services/detection/index.js +7 -0
  79. package/dist/services/detection/index.js.map +1 -0
  80. package/dist/services/docker/__tests__/docker-manager.test.d.ts +5 -0
  81. package/dist/services/docker/__tests__/docker-manager.test.d.ts.map +1 -0
  82. package/dist/services/docker/__tests__/docker-manager.test.js +67 -0
  83. package/dist/services/docker/__tests__/docker-manager.test.js.map +1 -0
  84. package/dist/services/docker/docker-manager.d.ts +157 -0
  85. package/dist/services/docker/docker-manager.d.ts.map +1 -0
  86. package/dist/services/docker/docker-manager.js +516 -0
  87. package/dist/services/docker/docker-manager.js.map +1 -0
  88. package/dist/services/docker/index.d.ts +9 -0
  89. package/dist/services/docker/index.d.ts.map +1 -0
  90. package/dist/services/docker/index.js +9 -0
  91. package/dist/services/docker/index.js.map +1 -0
  92. package/dist/services/index.d.ts +10 -0
  93. package/dist/services/index.d.ts.map +1 -0
  94. package/dist/services/index.js +8 -0
  95. package/dist/services/index.js.map +1 -0
  96. package/dist/shared/errors/__tests__/base.error.test.d.ts +5 -0
  97. package/dist/shared/errors/__tests__/base.error.test.d.ts.map +1 -0
  98. package/dist/shared/errors/__tests__/base.error.test.js +61 -0
  99. package/dist/shared/errors/__tests__/base.error.test.js.map +1 -0
  100. package/dist/shared/errors/__tests__/command.error.test.d.ts +5 -0
  101. package/dist/shared/errors/__tests__/command.error.test.d.ts.map +1 -0
  102. package/dist/shared/errors/__tests__/command.error.test.js +62 -0
  103. package/dist/shared/errors/__tests__/command.error.test.js.map +1 -0
  104. package/dist/shared/errors/__tests__/file.error.test.d.ts +5 -0
  105. package/dist/shared/errors/__tests__/file.error.test.d.ts.map +1 -0
  106. package/dist/shared/errors/__tests__/file.error.test.js +75 -0
  107. package/dist/shared/errors/__tests__/file.error.test.js.map +1 -0
  108. package/dist/shared/errors/__tests__/index.test.d.ts +5 -0
  109. package/dist/shared/errors/__tests__/index.test.d.ts.map +1 -0
  110. package/dist/shared/errors/__tests__/index.test.js +62 -0
  111. package/dist/shared/errors/__tests__/index.test.js.map +1 -0
  112. package/dist/shared/errors/__tests__/validation.error.test.d.ts +5 -0
  113. package/dist/shared/errors/__tests__/validation.error.test.d.ts.map +1 -0
  114. package/dist/shared/errors/__tests__/validation.error.test.js +79 -0
  115. package/dist/shared/errors/__tests__/validation.error.test.js.map +1 -0
  116. package/dist/shared/errors/base.error.d.ts +54 -0
  117. package/dist/shared/errors/base.error.d.ts.map +1 -0
  118. package/dist/shared/errors/base.error.js +85 -0
  119. package/dist/shared/errors/base.error.js.map +1 -0
  120. package/dist/shared/errors/command.error.d.ts +58 -0
  121. package/dist/shared/errors/command.error.d.ts.map +1 -0
  122. package/dist/shared/errors/command.error.js +102 -0
  123. package/dist/shared/errors/command.error.js.map +1 -0
  124. package/dist/shared/errors/detection.error.d.ts +42 -0
  125. package/dist/shared/errors/detection.error.d.ts.map +1 -0
  126. package/dist/shared/errors/detection.error.js +82 -0
  127. package/dist/shared/errors/detection.error.js.map +1 -0
  128. package/dist/shared/errors/docker.error.d.ts +142 -0
  129. package/dist/shared/errors/docker.error.d.ts.map +1 -0
  130. package/dist/shared/errors/docker.error.js +172 -0
  131. package/dist/shared/errors/docker.error.js.map +1 -0
  132. package/dist/shared/errors/file.error.d.ts +66 -0
  133. package/dist/shared/errors/file.error.d.ts.map +1 -0
  134. package/dist/shared/errors/file.error.js +93 -0
  135. package/dist/shared/errors/file.error.js.map +1 -0
  136. package/dist/shared/errors/index.d.ts +56 -0
  137. package/dist/shared/errors/index.d.ts.map +1 -0
  138. package/dist/shared/errors/index.js +86 -0
  139. package/dist/shared/errors/index.js.map +1 -0
  140. package/dist/shared/errors/validation.error.d.ts +67 -0
  141. package/dist/shared/errors/validation.error.d.ts.map +1 -0
  142. package/dist/shared/errors/validation.error.js +97 -0
  143. package/dist/shared/errors/validation.error.js.map +1 -0
  144. package/dist/shared/templates/index.d.ts +2 -0
  145. package/dist/shared/templates/index.d.ts.map +1 -0
  146. package/dist/shared/templates/index.js +2 -0
  147. package/dist/shared/templates/index.js.map +1 -0
  148. package/dist/shared/templates/prompt-builder.d.ts +2 -0
  149. package/dist/shared/templates/prompt-builder.d.ts.map +1 -0
  150. package/dist/shared/templates/prompt-builder.js +2 -0
  151. package/dist/shared/templates/prompt-builder.js.map +1 -0
  152. package/dist/shared/templates/template-engine.d.ts +2 -0
  153. package/dist/shared/templates/template-engine.d.ts.map +1 -0
  154. package/dist/shared/templates/template-engine.js +2 -0
  155. package/dist/shared/templates/template-engine.js.map +1 -0
  156. package/dist/shared/utils/__tests__/command-executor.test.d.ts +5 -0
  157. package/dist/shared/utils/__tests__/command-executor.test.d.ts.map +1 -0
  158. package/dist/shared/utils/__tests__/command-executor.test.js +45 -0
  159. package/dist/shared/utils/__tests__/command-executor.test.js.map +1 -0
  160. package/dist/shared/utils/__tests__/file-helper.test.d.ts +5 -0
  161. package/dist/shared/utils/__tests__/file-helper.test.d.ts.map +1 -0
  162. package/dist/shared/utils/__tests__/file-helper.test.js +71 -0
  163. package/dist/shared/utils/__tests__/file-helper.test.js.map +1 -0
  164. package/dist/shared/utils/__tests__/logger.test.d.ts +5 -0
  165. package/dist/shared/utils/__tests__/logger.test.d.ts.map +1 -0
  166. package/dist/shared/utils/__tests__/logger.test.js +83 -0
  167. package/dist/shared/utils/__tests__/logger.test.js.map +1 -0
  168. package/dist/shared/utils/command-executer.d.ts +2 -0
  169. package/dist/shared/utils/command-executer.d.ts.map +1 -0
  170. package/dist/shared/utils/command-executer.js +2 -0
  171. package/dist/shared/utils/command-executer.js.map +1 -0
  172. package/dist/shared/utils/command-executor.d.ts +255 -0
  173. package/dist/shared/utils/command-executor.d.ts.map +1 -0
  174. package/dist/shared/utils/command-executor.js +287 -0
  175. package/dist/shared/utils/command-executor.js.map +1 -0
  176. package/dist/shared/utils/file-helper.d.ts +86 -0
  177. package/dist/shared/utils/file-helper.d.ts.map +1 -0
  178. package/dist/shared/utils/file-helper.js +323 -0
  179. package/dist/shared/utils/file-helper.js.map +1 -0
  180. package/dist/shared/utils/index.d.ts +9 -0
  181. package/dist/shared/utils/index.d.ts.map +1 -0
  182. package/dist/shared/utils/index.js +9 -0
  183. package/dist/shared/utils/index.js.map +1 -0
  184. package/dist/shared/utils/logger.d.ts +163 -0
  185. package/dist/shared/utils/logger.d.ts.map +1 -0
  186. package/dist/shared/utils/logger.js +389 -0
  187. package/dist/shared/utils/logger.js.map +1 -0
  188. package/package.json +53 -34
  189. package/prompts/DEPS_EFFICIENCY.md +558 -558
  190. package/prompts/E2E.md +491 -491
  191. package/prompts/EXECUTE.md +1060 -1060
  192. package/prompts/INTEGRATION_API.md +484 -484
  193. package/prompts/INTEGRATION_DB.md +425 -425
  194. package/prompts/PERF_API.md +433 -433
  195. package/prompts/PERF_DB.md +430 -430
  196. package/prompts/PERF_FRONT.md +357 -357
  197. package/prompts/REMEDIATION.md +482 -482
  198. package/prompts/UNIT.md +260 -260
  199. package/templates/README.md +38 -38
  200. package/templates/k6/load-test.js +54 -54
  201. package/templates/playwright/e2e.spec.ts +61 -61
  202. package/templates/vitest/angular-component.test.ts +38 -38
  203. package/templates/vitest/api.test.ts +51 -51
  204. package/templates/vitest/component.test.ts +27 -27
  205. package/templates/vitest/hook.test.ts +36 -36
  206. package/templates/vitest/solid-component.test.ts +34 -34
  207. package/templates/vitest/svelte-component.test.ts +33 -33
  208. package/templates/vitest/vue-component.test.ts +39 -39
  209. package/CHANGELOG.md +0 -38
  210. package/agents/deps-analyzer.js +0 -366
  211. package/agents/detector.js +0 -570
  212. package/agents/fix-engine.js +0 -305
  213. package/agents/lighthouse-scanner.js +0 -405
  214. package/agents/perf-analyzer.js +0 -294
  215. package/agents/perf-front-analyzer.js +0 -229
  216. package/agents/test-generator.js +0 -387
  217. package/agents/test-runner.js +0 -318
  218. package/bin/cli.js +0 -449
  219. package/lib/config.js +0 -250
  220. package/lib/docker.js +0 -207
  221. package/lib/reporter.js +0 -297
  222. package/scripts/dev.js +0 -106
@@ -1,33 +1,33 @@
1
- import { render, screen } from '@testing-library/svelte';
2
- import { describe, it, expect, vi } from 'vitest';
3
-
4
- // TODO: Import your component
5
- // import ComponentName from '@/components/ComponentName.svelte';
6
-
7
- describe('ComponentName', () => {
8
- it('should render', () => {
9
- // TODO: Add component render
10
- // render(ComponentName);
11
- // expect(container).toBeTruthy();
12
- });
13
-
14
- it('should render with props', () => {
15
- // TODO: Test props
16
- // const { container } = render(ComponentName, { props: { title: 'Test Title' } });
17
- // expect(container.textContent).toContain('Test Title');
18
- });
19
-
20
- it('should handle user interaction', async () => {
21
- // TODO: Test events
22
- // const { container, component } = render(ComponentName);
23
- // const button = container.querySelector('button');
24
- // button.click();
25
- // expect(component.$$).toBeDefined();
26
- });
27
-
28
- it('should update when props change', async () => {
29
- // TODO: Test reactivity
30
- // const { container } = render(ComponentName, { props: { count: 0 } });
31
- // // Update props and check reactivity
32
- });
33
- });
1
+ import { render, screen } from '@testing-library/svelte';
2
+ import { describe, it, expect, vi } from 'vitest';
3
+
4
+ // TODO: Import your component
5
+ // import ComponentName from '@/components/ComponentName.svelte';
6
+
7
+ describe('ComponentName', () => {
8
+ it('should render', () => {
9
+ // TODO: Add component render
10
+ // render(ComponentName);
11
+ // expect(container).toBeTruthy();
12
+ });
13
+
14
+ it('should render with props', () => {
15
+ // TODO: Test props
16
+ // const { container } = render(ComponentName, { props: { title: 'Test Title' } });
17
+ // expect(container.textContent).toContain('Test Title');
18
+ });
19
+
20
+ it('should handle user interaction', async () => {
21
+ // TODO: Test events
22
+ // const { container, component } = render(ComponentName);
23
+ // const button = container.querySelector('button');
24
+ // button.click();
25
+ // expect(component.$$).toBeDefined();
26
+ });
27
+
28
+ it('should update when props change', async () => {
29
+ // TODO: Test reactivity
30
+ // const { container } = render(ComponentName, { props: { count: 0 } });
31
+ // // Update props and check reactivity
32
+ });
33
+ });
@@ -1,39 +1,39 @@
1
- import { mount } from '@vue/test-utils';
2
- import { describe, it, expect, vi } from 'vitest';
3
-
4
- // TODO: Import your component
5
- // import ComponentName from '@/components/ComponentName.vue';
6
-
7
- describe('ComponentName', () => {
8
- it('should render', () => {
9
- // TODO: Add component render
10
- // const wrapper = mount(ComponentName);
11
- // expect(wrapper.exists()).toBe(true);
12
- });
13
-
14
- it('should render with props', () => {
15
- // TODO: Test props
16
- // const wrapper = mount(ComponentName, {
17
- // props: { title: 'Test Title' }
18
- // });
19
- // expect(wrapper.text()).toContain('Test Title');
20
- });
21
-
22
- it('should handle user interaction', async () => {
23
- // TODO: Test events
24
- // const wrapper = mount(ComponentName, {
25
- // props: { onClick: vi.fn() }
26
- // });
27
- // await wrapper.find('button').trigger('click');
28
- // expect(wrapper.emitted('click')).toBeTruthy();
29
- });
30
-
31
- it('should update when props change', async () => {
32
- // TODO: Test reactivity
33
- // const wrapper = mount(ComponentName, {
34
- // props: { count: 0 }
35
- // });
36
- // await wrapper.setProps({ count: 5 });
37
- // expect(wrapper.text()).toContain('5');
38
- });
39
- });
1
+ import { mount } from '@vue/test-utils';
2
+ import { describe, it, expect, vi } from 'vitest';
3
+
4
+ // TODO: Import your component
5
+ // import ComponentName from '@/components/ComponentName.vue';
6
+
7
+ describe('ComponentName', () => {
8
+ it('should render', () => {
9
+ // TODO: Add component render
10
+ // const wrapper = mount(ComponentName);
11
+ // expect(wrapper.exists()).toBe(true);
12
+ });
13
+
14
+ it('should render with props', () => {
15
+ // TODO: Test props
16
+ // const wrapper = mount(ComponentName, {
17
+ // props: { title: 'Test Title' }
18
+ // });
19
+ // expect(wrapper.text()).toContain('Test Title');
20
+ });
21
+
22
+ it('should handle user interaction', async () => {
23
+ // TODO: Test events
24
+ // const wrapper = mount(ComponentName, {
25
+ // props: { onClick: vi.fn() }
26
+ // });
27
+ // await wrapper.find('button').trigger('click');
28
+ // expect(wrapper.emitted('click')).toBeTruthy();
29
+ });
30
+
31
+ it('should update when props change', async () => {
32
+ // TODO: Test reactivity
33
+ // const wrapper = mount(ComponentName, {
34
+ // props: { count: 0 }
35
+ // });
36
+ // await wrapper.setProps({ count: 5 });
37
+ // expect(wrapper.text()).toContain('5');
38
+ });
39
+ });
package/CHANGELOG.md DELETED
@@ -1,38 +0,0 @@
1
- # Daemon - Changelog
2
-
3
- ## [1.0.0-alpha] - 2025-02-07
4
-
5
- ### Added
6
- - Initial release
7
- - Auto-detection for frameworks (Next.js, Remix, SvelteKit, Vite, etc.)
8
- - Database detection (Prisma, Drizzle, Neon, Supabase, local Postgres)
9
- - Unit test generation (components, hooks, utils)
10
- - Integration test templates (API routes, DB with transaction rollback)
11
- - E2E test templates (Playwright)
12
- - Performance test templates (k6)
13
- - Dependency efficiency analysis (TanStack Router, React Query, Prisma, Zustand, React Compiler)
14
- - Docker container with all testing tools
15
- - Cross-platform support (Linux, macOS, Windows)
16
-
17
- ### Features
18
- - **Unit Tests**: Component, hook, and utility testing with Vitest
19
- - **Integration Tests**: API route and database testing with Prisma
20
- - **E2E Tests**: User flow testing with Playwright
21
- - **Performance Tests**: API load testing with k6
22
- - **Analysis**: Dependency pattern analysis and recommendations
23
- - **Remediation**: Automatic test failure categorization and fix suggestions
24
-
25
- ### Tools Included
26
- - Vitest
27
- - @testing-library/react
28
- - Playwright
29
- - k6
30
- - supertest
31
- - MSW
32
- - @prisma/cli
33
-
34
- ### Documentation
35
- - Comprehensive prompt system for AI agent
36
- - Test templates for all test types
37
- - Fix engine for common test failures
38
- - Performance analysis and reporting
@@ -1,366 +0,0 @@
1
- /**
2
- * Daemon - Dependency Efficiency Analyzer
3
- *
4
- * Analyzes codebase for dependency usage patterns and inefficiencies:
5
- * - TanStack Router patterns
6
- * - React Query usage
7
- * - Prisma query patterns
8
- * - Zustand store patterns
9
- * - React Compiler readiness
10
- */
11
-
12
- const fs = require('fs');
13
- const path = require('path');
14
-
15
- /**
16
- * Find files matching a pattern
17
- */
18
- function findFiles(dir, pattern, excludeDirs = ['node_modules', '.next', 'dist', 'build']) {
19
- const files = [];
20
-
21
- function traverse(currentDir) {
22
- if (!fs.existsSync(currentDir)) return;
23
-
24
- const entries = fs.readdirSync(currentDir, { withFileTypes: true });
25
-
26
- for (const entry of entries) {
27
- if (entry.isDirectory()) {
28
- if (excludeDirs.includes(entry.name)) continue;
29
- traverse(path.join(currentDir, entry.name));
30
- } else if (entry.isFile() && entry.name.match(pattern)) {
31
- files.push(path.join(currentDir, entry.name));
32
- }
33
- }
34
- }
35
-
36
- traverse(dir);
37
- return files;
38
- }
39
-
40
- /**
41
- * Read file content
42
- */
43
- function readFile(filePath) {
44
- try {
45
- return fs.readFileSync(filePath, 'utf-8');
46
- } catch {
47
- return '';
48
- }
49
- }
50
-
51
- /**
52
- * Analyze TanStack Router usage
53
- */
54
- function analyzeTanStackRouter(projectDir) {
55
- const findings = {
56
- good: [],
57
- issues: [],
58
- recommendations: [],
59
- };
60
-
61
- const routeFiles = findFiles(path.join(projectDir, 'src'), /routes/);
62
-
63
- for (const file of routeFiles) {
64
- const content = readFile(file);
65
-
66
- // Check for typed routes
67
- if (content.includes('useParams') || content.includes('$')) {
68
- findings.good.push(`Typed params in ${path.relative(projectDir, file)}`);
69
- }
70
-
71
- // Check for loaders
72
- if (content.includes('loader:') || content.includes('loaderBefore')) {
73
- findings.good.push(`Data loader in ${path.relative(projectDir, file)}`);
74
- } else if (content.includes('useQuery') || content.includes('useFetch')) {
75
- findings.issues.push(`Missing loader in ${path.relative(projectDir, file)} - data fetching without loader`);
76
- }
77
-
78
- // Check for error boundaries
79
- if (content.includes('loader:') && !content.includes('errorComponent') && !content.includes('ErrorBoundary')) {
80
- findings.issues.push(`Missing error boundary in ${path.relative(projectDir, file)}`);
81
- findings.recommendations.push(`Add errorComponent to route in ${path.relative(projectDir, file)}`);
82
- }
83
- }
84
-
85
- // Check navigation for prefetching
86
- const componentFiles = findFiles(path.join(projectDir, 'src'), /.*\.(tsx|jsx)$/);
87
- for (const file of componentFiles) {
88
- const content = readFile(file);
89
- if (content.includes('<Link') && !content.includes('prefetch=') && !content.includes('prefetchIntent')) {
90
- findings.issues.push(`Link prefetching not enabled in ${path.relative(projectDir, file)}`);
91
- }
92
- }
93
-
94
- return findings;
95
- }
96
-
97
- /**
98
- * Analyze React Query usage
99
- */
100
- function analyzeReactQuery(projectDir) {
101
- const findings = {
102
- good: [],
103
- issues: [],
104
- recommendations: [],
105
- };
106
-
107
- const hookFiles = findFiles(path.join(projectDir, 'src'), /hooks/);
108
- const componentFiles = findFiles(path.join(projectDir, 'src'), /.*\.(tsx|jsx)$/);
109
- const allFiles = [...hookFiles, ...componentFiles];
110
-
111
- for (const file of allFiles) {
112
- const content = readFile(file);
113
-
114
- if (!content.includes('useQuery') && !content.includes('useMutation')) continue;
115
-
116
- // Check for array cache keys
117
- if (content.includes('useQuery(') || content.includes('useInfiniteQuery(')) {
118
- const hasArrayKey = /\['/.test(content) || /queryKey:\s*\[/.test(content);
119
- if (hasArrayKey) {
120
- findings.good.push(`Array-based cache keys in ${path.relative(projectDir, file)}`);
121
- } else {
122
- findings.issues.push(`Non-array cache keys in ${path.relative(projectDir, file)}`);
123
- findings.recommendations.push(`Use array-based cache keys in ${path.relative(projectDir, file)}`);
124
- }
125
- }
126
-
127
- // Check for staleTime
128
- if (content.includes('useQuery(') && !content.includes('staleTime')) {
129
- findings.issues.push(`Missing staleTime in ${path.relative(projectDir, file)}`);
130
- findings.recommendations.push(`Add staleTime to queries in ${path.relative(projectDir, file)}`);
131
- }
132
-
133
- // Check for mutation invalidation
134
- if (content.includes('useMutation(')) {
135
- if (content.includes('invalidateQueries')) {
136
- findings.good.push(`Proper invalidation in ${path.relative(projectDir, file)}`);
137
- } else {
138
- findings.issues.push(`Missing invalidation in mutation at ${path.relative(projectDir, file)}`);
139
- }
140
- }
141
- }
142
-
143
- return findings;
144
- }
145
-
146
- /**
147
- * Analyze Prisma usage
148
- */
149
- function analyzePrisma(projectDir) {
150
- const findings = {
151
- good: [],
152
- issues: [],
153
- recommendations: [],
154
- };
155
-
156
- const libFiles = findFiles(path.join(projectDir, 'src'), /.*\.(ts|js)$/);
157
-
158
- for (const file of libFiles) {
159
- const content = readFile(file);
160
-
161
- if (!content.includes('prisma.')) continue;
162
-
163
- // Check for select usage
164
- if (content.includes('prisma.') && content.includes('findMany')) {
165
- if (content.includes('select:')) {
166
- findings.good.push(`Using select in ${path.relative(projectDir, file)}`);
167
- } else if (content.includes('.findMany().then')) {
168
- findings.issues.push(`Not using select in ${path.relative(projectDir, file)} - returning full objects`);
169
- findings.recommendations.push(`Add select to prisma queries in ${path.relative(projectDir, file)}`);
170
- }
171
- }
172
-
173
- // Check for potential N+1
174
- const lines = content.split('\n');
175
- for (let i = 0; i < lines.length; i++) {
176
- if (lines[i].includes('findMany') || lines[i].includes('findFirst')) {
177
- // Check next 10 lines for forEach with prisma query
178
- for (let j = i + 1; j < Math.min(i + 10, lines.length); j++) {
179
- if (lines[j].includes('forEach') && lines[j].includes('prisma.')) {
180
- findings.issues.push(`Potential N+1 query in ${path.relative(projectDir, file)}:${i + 1}`);
181
- findings.recommendations.push(`Use include or separate query with WHERE in ${path.relative(projectDir, file)}`);
182
- break;
183
- }
184
- }
185
- }
186
- }
187
- }
188
-
189
- // Check schema for indexes
190
- const schemaPath = path.join(projectDir, 'prisma', 'schema.prisma');
191
- if (fs.existsSync(schemaPath)) {
192
- const schema = readFile(schemaPath);
193
- const models = schema.matchAll(/model\s+(\w+)\s*{([^}]+)}/g);
194
-
195
- for (const modelMatch of models) {
196
- const modelName = modelMatch[1];
197
- const body = modelMatch[2];
198
-
199
- if (body.includes('email') && !body.includes('@@index') && !body.includes('@@unique')) {
200
- findings.recommendations.push(`Add index on ${modelName}.email for faster lookups`);
201
- }
202
- }
203
- }
204
-
205
- return findings;
206
- }
207
-
208
- /**
209
- * Analyze Zustand usage
210
- */
211
- function analyzeZustand(projectDir) {
212
- const findings = {
213
- good: [],
214
- issues: [],
215
- recommendations: [],
216
- };
217
-
218
- const storeFiles = findFiles(path.join(projectDir, 'src'), /store|stores/);
219
- const componentFiles = findFiles(path.join(projectDir, 'src'), /.*\.(tsx|jsx)$/);
220
-
221
- for (const file of storeFiles) {
222
- const content = readFile(file);
223
-
224
- // Check store size
225
- const lines = content.split('\n').length;
226
- if (lines > 500) {
227
- findings.issues.push(`Large store file ${path.relative(projectDir, file)} (${lines} lines)`);
228
- findings.recommendations.push(`Consider splitting ${path.basename(file)} into multiple stores`);
229
- }
230
- }
231
-
232
- for (const file of componentFiles) {
233
- const content = readFile(file);
234
-
235
- if (!content.includes('useStore')) continue;
236
-
237
- // Check for full-store subscriptions
238
- if (content.includes('useStore()') || content.match(/useStore\(\s*state\s*=>\s*state/)) {
239
- findings.issues.push(`Full-store subscription in ${path.relative(projectDir, file)}`);
240
- findings.recommendations.push(`Use selectors for specific fields in ${path.relative(projectDir, file)}`);
241
- }
242
- }
243
-
244
- return findings;
245
- }
246
-
247
- /**
248
- * Analyze React Compiler readiness
249
- */
250
- function analyzeReactCompilerReadiness(projectDir) {
251
- const findings = {
252
- good: [],
253
- issues: [],
254
- recommendations: [],
255
- };
256
-
257
- const componentFiles = findFiles(path.join(projectDir, 'src'), /.*\.(tsx|jsx)$/);
258
-
259
- for (const file of componentFiles) {
260
- const content = readFile(file);
261
-
262
- // Check for simple useMemo that can be removed
263
- const simpleMemo = content.match(/useMemo\(\(\)\s*=>\s*([^,]+),\s*\[[^\]]*\]\)/g);
264
- if (simpleMemo) {
265
- for (const memo of simpleMemo) {
266
- const value = memo.match(/=>\s*(.+),/)?.[1];
267
- if (value && !value.includes('()') && !value.includes('function')) {
268
- findings.recommendations.push(`Remove simple useMemo in ${path.basename(file)} - React Compiler will handle this`);
269
- }
270
- }
271
- }
272
-
273
- // Check for useCallback dependencies
274
- const useCallbacks = content.matchAll(/useCallback\([^)]+\)/g);
275
- for (const callback of useCallbacks) {
276
- const deps = callback[0].match(/\[([^\]]*)\]/)?.[1];
277
- if (deps && deps.trim() === '') {
278
- findings.issues.push(`useCallback with empty deps in ${path.basename(file)}`);
279
- }
280
- }
281
-
282
- // Check for large inline objects
283
- const largeObjects = content.match(/{{[\s\S]{200,}}}/g);
284
- if (largeObjects) {
285
- findings.issues.push(`Large inline object in ${path.basename(file)} - move outside component`);
286
- findings.recommendations.push(`Extract large objects to constants in ${path.basename(file)}`);
287
- }
288
- }
289
-
290
- return findings;
291
- }
292
-
293
- /**
294
- * Analyze bundle optimization
295
- */
296
- function analyzeBundleOptimization(projectDir) {
297
- const findings = {
298
- good: [],
299
- issues: [],
300
- recommendations: [],
301
- };
302
-
303
- const files = findFiles(path.join(projectDir, 'src'), /.*\.(ts|tsx|js|jsx)$/);
304
-
305
- for (const file of files) {
306
- const content = readFile(file);
307
-
308
- // Check for namespace imports
309
- if (content.includes('* as ')) {
310
- findings.issues.push(`Namespace import in ${path.basename(file)}`);
311
- findings.recommendations.push(`Use named imports for better tree-shaking in ${path.basename(file)}`);
312
- }
313
-
314
- // Check for large library imports
315
- const largeLibs = ['monaco-editor', 'codemirror', 'pdfjs-dist', 'fabric'];
316
- for (const lib of largeLibs) {
317
- if (content.includes(`from '${lib}'`) || content.includes(`from "${lib}"`)) {
318
- if (!content.includes('dynamic(') && !content.includes('React.lazy')) {
319
- findings.recommendations.push(`Use dynamic import for ${lib} in ${path.basename(file)}`);
320
- }
321
- }
322
- }
323
- }
324
-
325
- // Check package.json for duplicate dependencies
326
- const pkgPath = path.join(projectDir, 'package.json');
327
- if (fs.existsSync(pkgPath)) {
328
- const pkg = JSON.parse(readFile(pkgPath));
329
- const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
330
-
331
- for (const [name, version] of Object.entries(deps)) {
332
- if (name.startsWith('@types/')) {
333
- const mainPkg = name.substring(6);
334
- if (mainPkg in deps) {
335
- findings.good.push(`Types package for ${mainPkg} found`);
336
- }
337
- }
338
- }
339
- }
340
-
341
- return findings;
342
- }
343
-
344
- /**
345
- * Run full analysis
346
- */
347
- function analyze(projectDir) {
348
- return {
349
- tanStackRouter: analyzeTanStackRouter(projectDir),
350
- reactQuery: analyzeReactQuery(projectDir),
351
- prisma: analyzePrisma(projectDir),
352
- zustand: analyzeZustand(projectDir),
353
- reactCompiler: analyzeReactCompilerReadiness(projectDir),
354
- bundleOptimization: analyzeBundleOptimization(projectDir),
355
- };
356
- }
357
-
358
- module.exports = {
359
- analyze,
360
- analyzeTanStackRouter,
361
- analyzeReactQuery,
362
- analyzePrisma,
363
- analyzeZustand,
364
- analyzeReactCompilerReadiness,
365
- analyzeBundleOptimization,
366
- };