@rigour-labs/core 4.0.0 → 4.0.2

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.
@@ -0,0 +1,220 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildAnalysisPrompt, buildCrossFilePrompt, chunkFacts, DEEP_SYSTEM_PROMPT } from './prompts.js';
3
+ // ── Test helpers ──
4
+ function makeGoFacts(overrides = {}) {
5
+ return {
6
+ path: 'pkg/server.go',
7
+ language: 'go',
8
+ lineCount: 200,
9
+ classes: [],
10
+ functions: [{
11
+ name: 'Server.Start',
12
+ lineStart: 10,
13
+ lineEnd: 50,
14
+ lineCount: 40,
15
+ paramCount: 1,
16
+ params: ['ctx context.Context'],
17
+ maxNesting: 3,
18
+ hasReturn: true,
19
+ isAsync: false,
20
+ isExported: true,
21
+ }],
22
+ imports: ['net/http', 'context', 'sync'],
23
+ exports: [],
24
+ errorHandling: [],
25
+ testAssertions: 0,
26
+ hasTests: false,
27
+ structs: [{
28
+ name: 'Server',
29
+ lineStart: 5,
30
+ lineEnd: 15,
31
+ fieldCount: 5,
32
+ methodCount: 4,
33
+ methods: ['Start', 'Stop', 'Handle', 'Route'],
34
+ lineCount: 10,
35
+ embeds: ['BaseServer'],
36
+ }],
37
+ interfaces: [{
38
+ name: 'Handler',
39
+ lineStart: 20,
40
+ methodCount: 2,
41
+ methods: ['ServeHTTP', 'Health'],
42
+ }],
43
+ goroutines: 3,
44
+ channels: 1,
45
+ mutexes: 1,
46
+ defers: 2,
47
+ ...overrides,
48
+ };
49
+ }
50
+ function makeTsFacts(overrides = {}) {
51
+ return {
52
+ path: 'src/service.ts',
53
+ language: 'typescript',
54
+ lineCount: 150,
55
+ classes: [{
56
+ name: 'UserService',
57
+ lineStart: 5,
58
+ lineEnd: 140,
59
+ methodCount: 6,
60
+ methods: ['find', 'create', 'update', 'delete', 'validate', 'notify'],
61
+ publicMethods: ['find', 'create', 'update', 'delete'],
62
+ lineCount: 135,
63
+ dependencies: ['Database', 'Logger'],
64
+ }],
65
+ functions: [],
66
+ imports: ['express', 'lodash', './types'],
67
+ exports: ['UserService'],
68
+ errorHandling: [
69
+ { type: 'try-catch', lineStart: 10, isEmpty: false, strategy: 'throw' },
70
+ ],
71
+ testAssertions: 0,
72
+ hasTests: false,
73
+ ...overrides,
74
+ };
75
+ }
76
+ describe('Deep Analysis Prompts', () => {
77
+ // ── DEEP_SYSTEM_PROMPT ──
78
+ describe('DEEP_SYSTEM_PROMPT', () => {
79
+ it('should contain all category groups', () => {
80
+ expect(DEEP_SYSTEM_PROMPT).toContain('SOLID Principles');
81
+ expect(DEEP_SYSTEM_PROMPT).toContain('Design Patterns');
82
+ expect(DEEP_SYSTEM_PROMPT).toContain('DRY');
83
+ expect(DEEP_SYSTEM_PROMPT).toContain('Error Handling');
84
+ expect(DEEP_SYSTEM_PROMPT).toContain('Concurrency');
85
+ expect(DEEP_SYSTEM_PROMPT).toContain('Testing');
86
+ });
87
+ it('should contain key category IDs', () => {
88
+ expect(DEEP_SYSTEM_PROMPT).toContain('god_class');
89
+ expect(DEEP_SYSTEM_PROMPT).toContain('god_function');
90
+ expect(DEEP_SYSTEM_PROMPT).toContain('srp_violation');
91
+ expect(DEEP_SYSTEM_PROMPT).toContain('race_condition');
92
+ expect(DEEP_SYSTEM_PROMPT).toContain('empty_catch');
93
+ expect(DEEP_SYSTEM_PROMPT).toContain('missing_test');
94
+ });
95
+ it('should include output schema', () => {
96
+ expect(DEEP_SYSTEM_PROMPT).toContain('"findings"');
97
+ expect(DEEP_SYSTEM_PROMPT).toContain('"category"');
98
+ expect(DEEP_SYSTEM_PROMPT).toContain('"severity"');
99
+ expect(DEEP_SYSTEM_PROMPT).toContain('"confidence"');
100
+ });
101
+ it('should contain Go-specific guidance', () => {
102
+ expect(DEEP_SYSTEM_PROMPT).toContain('Go code');
103
+ expect(DEEP_SYSTEM_PROMPT).toContain('struct');
104
+ expect(DEEP_SYSTEM_PROMPT).toContain('receiver method');
105
+ });
106
+ });
107
+ // ── buildAnalysisPrompt ──
108
+ describe('buildAnalysisPrompt', () => {
109
+ it('should build prompt with default checks', () => {
110
+ const factsStr = 'FILE: src/service.ts (typescript, 150 lines)';
111
+ const prompt = buildAnalysisPrompt(factsStr);
112
+ // Default checks include descriptions for SOLID, DRY, design patterns
113
+ expect(prompt).toContain('SOLID');
114
+ expect(prompt).toContain('DRY');
115
+ expect(prompt).toContain('god class');
116
+ expect(prompt).toContain(factsStr);
117
+ });
118
+ it('should include language-specific guidance for Go', () => {
119
+ const factsStr = 'FILE: pkg/server.go (go, 200 lines)\n STRUCT Server (10 lines, 5 fields)';
120
+ const prompt = buildAnalysisPrompt(factsStr);
121
+ // Should detect Go as dominant language and add Go guidance
122
+ expect(prompt.toLowerCase()).toContain('go');
123
+ });
124
+ it('should include language-specific guidance for TypeScript', () => {
125
+ const factsStr = 'FILE: src/service.ts (typescript, 150 lines)\n CLASS UserService';
126
+ const prompt = buildAnalysisPrompt(factsStr);
127
+ expect(prompt.toLowerCase()).toContain('typescript');
128
+ });
129
+ it('should respect custom check selection', () => {
130
+ const factsStr = 'FILE: src/service.ts (typescript, 150 lines)';
131
+ const checks = {
132
+ solid: true,
133
+ dry: false,
134
+ design_patterns: false,
135
+ concurrency: true,
136
+ };
137
+ const prompt = buildAnalysisPrompt(factsStr, checks);
138
+ expect(prompt).toContain('SOLID');
139
+ expect(prompt).toContain('Concurrency');
140
+ });
141
+ });
142
+ // ── buildCrossFilePrompt ──
143
+ describe('buildCrossFilePrompt', () => {
144
+ it('should analyze patterns across multiple files', () => {
145
+ const allFacts = [
146
+ makeTsFacts({ path: 'src/user.service.ts' }),
147
+ makeTsFacts({
148
+ path: 'src/order.service.ts',
149
+ classes: [{
150
+ name: 'OrderService',
151
+ lineStart: 1,
152
+ lineEnd: 100,
153
+ methodCount: 5,
154
+ methods: ['find', 'create', 'update', 'delete', 'process'],
155
+ publicMethods: ['find', 'create'],
156
+ lineCount: 100,
157
+ dependencies: ['Database', 'Logger'],
158
+ }],
159
+ }),
160
+ makeTsFacts({
161
+ path: 'src/product.service.ts',
162
+ errorHandling: [
163
+ { type: 'try-catch', lineStart: 5, isEmpty: false, strategy: 'log' },
164
+ { type: 'try-catch', lineStart: 15, isEmpty: false, strategy: 'throw' },
165
+ ],
166
+ }),
167
+ ];
168
+ const prompt = buildCrossFilePrompt(allFacts);
169
+ expect(prompt).toBeDefined();
170
+ expect(prompt.length).toBeGreaterThan(0);
171
+ // Should reference file count
172
+ expect(prompt).toContain('3');
173
+ });
174
+ it('should include Go-specific cross-file info', () => {
175
+ const allFacts = [
176
+ makeGoFacts({ path: 'pkg/server.go' }),
177
+ makeGoFacts({
178
+ path: 'pkg/handler.go',
179
+ structs: [{
180
+ name: 'Handler',
181
+ lineStart: 1,
182
+ lineEnd: 50,
183
+ fieldCount: 3,
184
+ methodCount: 5,
185
+ methods: ['Get', 'Post', 'Put', 'Delete', 'Options'],
186
+ lineCount: 50,
187
+ embeds: [],
188
+ }],
189
+ }),
190
+ ];
191
+ const prompt = buildCrossFilePrompt(allFacts);
192
+ expect(prompt).toBeDefined();
193
+ expect(prompt.length).toBeGreaterThan(0);
194
+ });
195
+ });
196
+ // ── chunkFacts ──
197
+ describe('chunkFacts', () => {
198
+ it('should split facts into token-limited chunks', () => {
199
+ const manyFacts = Array.from({ length: 50 }, (_, i) => makeTsFacts({
200
+ path: `src/file${i}.ts`,
201
+ lineCount: 200,
202
+ }));
203
+ const chunks = chunkFacts(manyFacts, 4000);
204
+ expect(chunks.length).toBeGreaterThan(1);
205
+ // All facts should be distributed across chunks
206
+ const totalFiles = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
207
+ expect(totalFiles).toBe(50);
208
+ });
209
+ it('should handle single file within budget', () => {
210
+ const facts = [makeTsFacts()];
211
+ const chunks = chunkFacts(facts, 10000);
212
+ expect(chunks).toHaveLength(1);
213
+ expect(chunks[0]).toHaveLength(1);
214
+ });
215
+ it('should handle empty input', () => {
216
+ const chunks = chunkFacts([], 4000);
217
+ expect(chunks).toHaveLength(0);
218
+ });
219
+ });
220
+ });
@@ -0,0 +1 @@
1
+ export {};