@boyingliu01/xp-gate 0.12.10 → 0.12.13
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/adapters/iac.sh +51 -24
- package/adapters/typescript.sh +87 -10
- package/bin/xp-gate.js +2 -2
- package/gate-3.sh +1 -1
- package/hooks/adapter-common.sh +13 -18
- package/hooks/pre-commit +166 -27
- package/hooks/pre-push +231 -18
- package/lib/__tests__/sprint-discovery.test.ts +5 -4
- package/lib/__tests__/sprint-status.test.ts +5 -4
- package/lib/__tests__/tsconfig.json +8 -0
- package/lib/init.js +97 -3
- package/mock-policy/AGENTS.md +3 -3
- package/mutation/AGENTS.md +3 -3
- package/package.json +1 -1
- package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-code/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/claude-code/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/opencode/package.json +1 -1
- package/plugins/opencode/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/opencode/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
- package/plugins/qoder/plugin.json +1 -1
- package/plugins/qoder/skills/delphi-review/AGENTS.md +3 -3
- package/plugins/qoder/skills/sprint-flow/AGENTS.md +3 -3
- package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
- package/principles/AGENTS.md +3 -3
- package/principles/__tests__/baseline-storage.test.ts +3 -2
- package/principles/__tests__/baseline.test.ts +16 -14
- package/principles/__tests__/types.test.ts +1 -0
- package/principles/adapters/__tests__/base.test.ts +8 -8
- package/principles/adapters/__tests__/cpp.test.ts +26 -26
- package/principles/adapters/__tests__/dart.test.ts +11 -11
- package/principles/adapters/__tests__/go.test.ts +9 -9
- package/principles/adapters/__tests__/java.test.ts +9 -9
- package/principles/adapters/__tests__/kotlin.test.ts +10 -10
- package/principles/adapters/__tests__/objectivec.test.ts +27 -27
- package/principles/adapters/__tests__/python.test.ts +11 -11
- package/principles/adapters/__tests__/swift.test.ts +9 -9
- package/principles/adapters/__tests__/typescript.test.ts +13 -13
- package/principles/rules/__tests__/clean-code/large-file.test.ts +4 -3
- package/skills/delphi-review/AGENTS.md +3 -3
- package/skills/sprint-flow/AGENTS.md +3 -3
- package/skills/test-specification-alignment/AGENTS.md +3 -3
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-07
|
|
4
|
+
**Commit:** 897f8eb
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.13.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xp-gate",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.13",
|
|
4
4
|
"displayName": "XP-Gate",
|
|
5
5
|
"description": "Extreme Programming quality gates + AI workflow skills for Qoder. Includes 10 quality gates (Gate 0-9), Sprint Flow (11 phases), and Delphi multi-expert review (>=90% consensus).",
|
|
6
6
|
"author": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-07
|
|
4
|
+
**Commit:** 897f8eb
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.13.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/SPRINT-FLOW KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-07
|
|
4
|
+
**Commit:** 897f8eb
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.13.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
**11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → USER ACCEPTANCE → FEEDBACK → SHIP → LAND → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: design must pass Delphi review (≥90% consensus) before any coding.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-07
|
|
4
|
+
**Commit:** 897f8eb
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.13.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.
|
package/principles/AGENTS.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# PRINCIPLES CHECKER MODULE
|
|
2
2
|
|
|
3
|
-
**Generated:** 2026-07-
|
|
4
|
-
**Commit:**
|
|
3
|
+
**Generated:** 2026-07-07
|
|
4
|
+
**Commit:** 897f8eb
|
|
5
5
|
**Branch:** main
|
|
6
|
-
**Version:** 0.12.
|
|
6
|
+
**Version:** 0.12.13.0
|
|
7
7
|
|
|
8
8
|
## OVERVIEW
|
|
9
9
|
Clean Code & SOLID principles checker — **Gate 4** of pre-commit. 14 rules × 9 language adapters, SARIF 2.1.0 output. Houses the **Boy Scout Rule** enforcement engine (Gate 6) and warning-baseline storage.
|
|
@@ -154,8 +154,9 @@ describe('Baseline Storage', () => {
|
|
|
154
154
|
expect(stats.totalFiles).toBe(2);
|
|
155
155
|
expect(stats.totalWarnings).toBe(7);
|
|
156
156
|
expect(stats.averageWarningsPerFile).toBe(3.5);
|
|
157
|
-
|
|
158
|
-
expect(
|
|
157
|
+
const richStats = stats as { totalFiles: number; totalWarnings: number; averageWarningsPerFile: number; eslint: { totalWarnings: number; totalErrors: number } };
|
|
158
|
+
expect(richStats.eslint.totalWarnings).toBe(6);
|
|
159
|
+
expect(richStats.eslint.totalErrors).toBe(1);
|
|
159
160
|
});
|
|
160
161
|
|
|
161
162
|
it('creates baseline from files with warning data', async () => {
|
|
@@ -19,7 +19,7 @@ describe('BaselineEntry - lint tool fields (ruff, golangci, shellcheck)', () =>
|
|
|
19
19
|
lastAnalyzed: new Date().toISOString(),
|
|
20
20
|
},
|
|
21
21
|
};
|
|
22
|
-
expect(() => storage.validate(entry as Record<string, import('../baseline').BaselineEntry>)).not.toThrow();
|
|
22
|
+
expect(() => storage.validate(entry as unknown as Record<string, import('../baseline').BaselineEntry>)).not.toThrow();
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
it('accepts golangci field in BaselineEntry', () => {
|
|
@@ -31,7 +31,7 @@ describe('BaselineEntry - lint tool fields (ruff, golangci, shellcheck)', () =>
|
|
|
31
31
|
lastAnalyzed: new Date().toISOString(),
|
|
32
32
|
},
|
|
33
33
|
};
|
|
34
|
-
expect(() => storage.validate(entry as Record<string, import('../baseline').BaselineEntry>)).not.toThrow();
|
|
34
|
+
expect(() => storage.validate(entry as unknown as Record<string, import('../baseline').BaselineEntry>)).not.toThrow();
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it('accepts shellcheck field in BaselineEntry', () => {
|
|
@@ -43,7 +43,7 @@ describe('BaselineEntry - lint tool fields (ruff, golangci, shellcheck)', () =>
|
|
|
43
43
|
lastAnalyzed: new Date().toISOString(),
|
|
44
44
|
},
|
|
45
45
|
};
|
|
46
|
-
expect(() => storage.validate(entry as Record<string, import('../baseline').BaselineEntry>)).not.toThrow();
|
|
46
|
+
expect(() => storage.validate(entry as unknown as Record<string, import('../baseline').BaselineEntry>)).not.toThrow();
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
it('rejects ruff entry with non-numeric warnings', () => {
|
|
@@ -55,7 +55,7 @@ describe('BaselineEntry - lint tool fields (ruff, golangci, shellcheck)', () =>
|
|
|
55
55
|
lastAnalyzed: new Date().toISOString(),
|
|
56
56
|
},
|
|
57
57
|
};
|
|
58
|
-
expect(() => storage.validate(entry as Record<string, import('../baseline').BaselineEntry>)).toThrow(/Invalid ruff properties/);
|
|
58
|
+
expect(() => storage.validate(entry as unknown as Record<string, import('../baseline').BaselineEntry>)).toThrow(/Invalid ruff properties/);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
it('combines all lint tools in getSummaryStatistics', () => {
|
|
@@ -82,12 +82,13 @@ describe('BaselineEntry - lint tool fields (ruff, golangci, shellcheck)', () =>
|
|
|
82
82
|
|
|
83
83
|
expect(stats.totalFiles).toBe(3);
|
|
84
84
|
expect(stats.totalWarnings).toBe(10);
|
|
85
|
-
|
|
86
|
-
expect(
|
|
87
|
-
expect(
|
|
88
|
-
expect(
|
|
89
|
-
expect(
|
|
90
|
-
expect(
|
|
85
|
+
const richStats = stats as typeof stats & { ruff: { totalWarnings: number; totalErrors: number }; golangci: { totalWarnings: number; totalErrors: number }; shellcheck: { totalWarnings: number; totalErrors: number } };
|
|
86
|
+
expect(richStats.ruff.totalWarnings).toBe(5);
|
|
87
|
+
expect(richStats.ruff.totalErrors).toBe(2);
|
|
88
|
+
expect(richStats.golangci.totalWarnings).toBe(3);
|
|
89
|
+
expect(richStats.golangci.totalErrors).toBe(1);
|
|
90
|
+
expect(richStats.shellcheck.totalWarnings).toBe(2);
|
|
91
|
+
expect(richStats.shellcheck.totalErrors).toBe(0);
|
|
91
92
|
});
|
|
92
93
|
});
|
|
93
94
|
|
|
@@ -121,11 +122,12 @@ describe('BaselineStorage - extended coverage', () => {
|
|
|
121
122
|
},
|
|
122
123
|
};
|
|
123
124
|
|
|
124
|
-
const
|
|
125
|
+
const rawStats = storage.getSummaryStatistics(baseline);
|
|
126
|
+
const stats = rawStats as { totalFiles: number; totalWarnings: number; averageWarningsPerFile: number; ccn: { totalWarnings: number; totalMax: number } };
|
|
125
127
|
|
|
126
128
|
expect(stats.totalFiles).toBe(2);
|
|
127
|
-
expect(stats.ccn
|
|
128
|
-
expect(stats.ccn
|
|
129
|
+
expect(stats.ccn.totalWarnings).toBe(8);
|
|
130
|
+
expect(stats.ccn.totalMax).toBe(30);
|
|
129
131
|
});
|
|
130
132
|
|
|
131
133
|
it('returns averageWarningsPerFile of 0 for empty baseline', () => {
|
|
@@ -135,7 +137,7 @@ describe('BaselineStorage - extended coverage', () => {
|
|
|
135
137
|
expect(stats.totalFiles).toBe(0);
|
|
136
138
|
expect(stats.totalWarnings).toBe(0);
|
|
137
139
|
expect(stats.averageWarningsPerFile).toBe(0);
|
|
138
|
-
expect(stats.ccn).toBeUndefined();
|
|
140
|
+
expect('ccn' in stats ? (stats as Record<string, unknown>).ccn : undefined).toBeUndefined();
|
|
139
141
|
});
|
|
140
142
|
});
|
|
141
143
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
1
|
+
import { describe, it, expect, vi, type Mock } from 'vitest';;
|
|
2
2
|
import type { Adapter } from '../../types';
|
|
3
3
|
import { BaseAdapter } from '../base';
|
|
4
4
|
|
|
@@ -24,7 +24,7 @@ import { readFileSync } from 'fs';
|
|
|
24
24
|
describe('BaseAdapter - Default Implementation', () => {
|
|
25
25
|
|
|
26
26
|
it('should implement the Adapter interface', () => {
|
|
27
|
-
(readFileSync as
|
|
27
|
+
(readFileSync as Mock).mockReturnValue('mock file content\ntest line 2');
|
|
28
28
|
const adapter = new MockAdapter('./test.ts');
|
|
29
29
|
const implemented: Adapter = adapter as unknown as Adapter;
|
|
30
30
|
|
|
@@ -37,7 +37,7 @@ describe('BaseAdapter - Default Implementation', () => {
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
it('should detect language based on file extension', () => {
|
|
40
|
-
(readFileSync as
|
|
40
|
+
(readFileSync as Mock).mockReturnValue('file content');
|
|
41
41
|
|
|
42
42
|
const adapterTs = new MockAdapter('./test.ts');
|
|
43
43
|
expect(adapterTs.detectLanguage()).toBe('typescript');
|
|
@@ -56,35 +56,35 @@ describe('BaseAdapter - Default Implementation', () => {
|
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
it('should parse file AST correctly', () => {
|
|
59
|
-
(readFileSync as
|
|
59
|
+
(readFileSync as Mock).mockReturnValue('mock file content\ntest line 2');
|
|
60
60
|
const adapter = new MockAdapter('./test.ts');
|
|
61
61
|
const ast = adapter.parseAST();
|
|
62
62
|
expect(ast).toEqual({ content: 'mock file content\ntest line 2', astType: 'mock' });
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
it('should extract functions from AST', () => {
|
|
66
|
-
(readFileSync as
|
|
66
|
+
(readFileSync as Mock).mockReturnValue('');
|
|
67
67
|
const adapter = new MockAdapter('./test.ts');
|
|
68
68
|
const functions = adapter.extractFunctions();
|
|
69
69
|
expect(Array.isArray(functions)).toBe(true);
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
it('should extract classes from AST', () => {
|
|
73
|
-
(readFileSync as
|
|
73
|
+
(readFileSync as Mock).mockReturnValue('');
|
|
74
74
|
const adapter = new MockAdapter('./test.ts');
|
|
75
75
|
const classes = adapter.extractClasses();
|
|
76
76
|
expect(Array.isArray(classes)).toBe(true);
|
|
77
77
|
});
|
|
78
78
|
|
|
79
79
|
it('should count physical lines correctly', () => {
|
|
80
|
-
(readFileSync as
|
|
80
|
+
(readFileSync as Mock).mockReturnValue('line 1\nline 2\nline 3');
|
|
81
81
|
const adapter = new MockAdapter('./test.ts');
|
|
82
82
|
const lineCount = adapter.countLines();
|
|
83
83
|
expect(lineCount).toBe(3);
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
it('should throw error for unsupported file operations', () => {
|
|
87
|
-
(readFileSync as
|
|
87
|
+
(readFileSync as Mock).mockImplementation(() => {
|
|
88
88
|
throw new Error('Could not read file');
|
|
89
89
|
});
|
|
90
90
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
1
|
+
import { describe, it, expect, vi, type Mock } from 'vitest';;
|
|
2
2
|
import { CppAdapter } from '../cpp';
|
|
3
3
|
|
|
4
4
|
type MockFunction = Record<string, unknown>;
|
|
@@ -13,7 +13,7 @@ import { readFileSync } from 'fs';
|
|
|
13
13
|
describe('CppAdapter', () => {
|
|
14
14
|
|
|
15
15
|
it('should implement the Adapter interface', () => {
|
|
16
|
-
(readFileSync as
|
|
16
|
+
(readFileSync as Mock).mockReturnValue('int main() { return 0; }');
|
|
17
17
|
const adapter = new CppAdapter('test.cpp');
|
|
18
18
|
|
|
19
19
|
expect(adapter).toHaveProperty('detectLanguage');
|
|
@@ -24,59 +24,59 @@ describe('CppAdapter', () => {
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
it('should detect language as cpp for .cpp files', () => {
|
|
27
|
-
(readFileSync as
|
|
27
|
+
(readFileSync as Mock).mockReturnValue('int main() { return 0; }');
|
|
28
28
|
const adapter = new CppAdapter('test.cpp');
|
|
29
29
|
const detected = adapter.detectLanguage();
|
|
30
30
|
expect(detected).toBe('cpp');
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('should detect language as cpp for .cxx files', () => {
|
|
34
|
-
(readFileSync as
|
|
34
|
+
(readFileSync as Mock).mockReturnValue('int main() { return 0; }');
|
|
35
35
|
const adapter = new CppAdapter('test.cxx');
|
|
36
36
|
const detected = adapter.detectLanguage();
|
|
37
37
|
expect(detected).toBe('cpp');
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it('should detect language as cpp for .cc files', () => {
|
|
41
|
-
(readFileSync as
|
|
41
|
+
(readFileSync as Mock).mockReturnValue('int main() { return 0; }');
|
|
42
42
|
const adapter = new CppAdapter('test.cc');
|
|
43
43
|
const detected = adapter.detectLanguage();
|
|
44
44
|
expect(detected).toBe('cpp');
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
it('should detect language as cpp for .c files', () => {
|
|
48
|
-
(readFileSync as
|
|
48
|
+
(readFileSync as Mock).mockReturnValue('int main() { return 0; }');
|
|
49
49
|
const adapter = new CppAdapter('test.c');
|
|
50
50
|
const detected = adapter.detectLanguage();
|
|
51
51
|
expect(detected).toBe('cpp');
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
it('should detect language as cpp for .hpp files', () => {
|
|
55
|
-
(readFileSync as
|
|
55
|
+
(readFileSync as Mock).mockReturnValue('#pragma once');
|
|
56
56
|
const adapter = new CppAdapter('test.hpp');
|
|
57
57
|
const detected = adapter.detectLanguage();
|
|
58
58
|
expect(detected).toBe('cpp');
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
it('should detect language as cpp for .h files', () => {
|
|
62
|
-
(readFileSync as
|
|
62
|
+
(readFileSync as Mock).mockReturnValue('#pragma once');
|
|
63
63
|
const adapter = new CppAdapter('test.h');
|
|
64
64
|
const detected = adapter.detectLanguage();
|
|
65
65
|
expect(detected).toBe('cpp');
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
it('should parse C++ file AST correctly', () => {
|
|
69
|
-
(readFileSync as
|
|
69
|
+
(readFileSync as Mock).mockReturnValue('int main() { return 0; }');
|
|
70
70
|
const adapter = new CppAdapter('test.cpp');
|
|
71
71
|
const ast = adapter.parseAST();
|
|
72
72
|
expect(ast).toHaveProperty('content');
|
|
73
73
|
expect(ast).toHaveProperty('language');
|
|
74
74
|
expect(ast).toHaveProperty('filePath');
|
|
75
|
-
expect(ast.language).toBe('cpp');
|
|
75
|
+
expect((ast as { language: unknown }).language).toBe('cpp');
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it('should extract functions from C++ code', () => {
|
|
79
|
-
(readFileSync as
|
|
79
|
+
(readFileSync as Mock).mockReturnValue(`
|
|
80
80
|
int add(int a, int b) {
|
|
81
81
|
return a + b;
|
|
82
82
|
}
|
|
@@ -92,7 +92,7 @@ int main() {
|
|
|
92
92
|
});
|
|
93
93
|
|
|
94
94
|
it('should handle C++ strings with special characters', () => {
|
|
95
|
-
(readFileSync as
|
|
95
|
+
(readFileSync as Mock).mockReturnValue(`
|
|
96
96
|
int main() {
|
|
97
97
|
const char* str = "Hello \\"World\\"";
|
|
98
98
|
char c = '\\'';
|
|
@@ -107,7 +107,7 @@ int main() {
|
|
|
107
107
|
});
|
|
108
108
|
|
|
109
109
|
it('should throw error when file cannot be read', () => {
|
|
110
|
-
(readFileSync as
|
|
110
|
+
(readFileSync as Mock).mockImplementation(() => {
|
|
111
111
|
throw new Error('Could not read file');
|
|
112
112
|
});
|
|
113
113
|
|
|
@@ -125,7 +125,7 @@ int main() {
|
|
|
125
125
|
describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
126
126
|
it('should skip single-line block comment before the opening brace', () => {
|
|
127
127
|
const src = `int foo() /* inline comment */ { return 1; }`;
|
|
128
|
-
(readFileSync as
|
|
128
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
129
129
|
const adapter = new CppAdapter('test.cpp');
|
|
130
130
|
const block = adapter.extractCodeBlock(0);
|
|
131
131
|
expect(block).toContain('{ return 1; }');
|
|
@@ -142,7 +142,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
142
142
|
' return 42;',
|
|
143
143
|
'}',
|
|
144
144
|
].join('\n');
|
|
145
|
-
(readFileSync as
|
|
145
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
146
146
|
const adapter = new CppAdapter('test.cpp');
|
|
147
147
|
const block = adapter.extractCodeBlock(0);
|
|
148
148
|
expect(block).toContain('return 42;');
|
|
@@ -151,7 +151,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
151
151
|
|
|
152
152
|
it('should ignore braces inside block comments', () => {
|
|
153
153
|
const src = `int foo() /* fake { brace } here */ { return 7; }`;
|
|
154
|
-
(readFileSync as
|
|
154
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
155
155
|
const adapter = new CppAdapter('test.cpp');
|
|
156
156
|
const block = adapter.extractCodeBlock(0);
|
|
157
157
|
expect(block).toContain('return 7;');
|
|
@@ -160,7 +160,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
160
160
|
|
|
161
161
|
it('should count nested braces correctly via braceCount++ path', () => {
|
|
162
162
|
const src = `void foo() { if (x) { return; } }`;
|
|
163
|
-
(readFileSync as
|
|
163
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
164
164
|
const adapter = new CppAdapter('test.cpp');
|
|
165
165
|
const block = adapter.extractCodeBlock(0);
|
|
166
166
|
expect(block).toBe('void foo() { if (x) { return; } }');
|
|
@@ -168,7 +168,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
168
168
|
|
|
169
169
|
it('should handle deeply nested braces (triple nesting)', () => {
|
|
170
170
|
const src = `int bar() { if (a) { while (b) { c++; } } return 0; }`;
|
|
171
|
-
(readFileSync as
|
|
171
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
172
172
|
const adapter = new CppAdapter('test.cpp');
|
|
173
173
|
const block = adapter.extractCodeBlock(0);
|
|
174
174
|
expect(block.trim().endsWith('}')).toBe(true);
|
|
@@ -190,7 +190,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
190
190
|
' return 0;',
|
|
191
191
|
'}',
|
|
192
192
|
].join('\n');
|
|
193
|
-
(readFileSync as
|
|
193
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
194
194
|
const adapter = new CppAdapter('test.cpp');
|
|
195
195
|
const block = adapter.extractCodeBlock(0);
|
|
196
196
|
expect(block.trim().endsWith('}')).toBe(true);
|
|
@@ -205,7 +205,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
205
205
|
' return 5;',
|
|
206
206
|
'}',
|
|
207
207
|
].join('\n');
|
|
208
|
-
(readFileSync as
|
|
208
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
209
209
|
const adapter = new CppAdapter('test.cpp');
|
|
210
210
|
const block = adapter.extractCodeBlock(0);
|
|
211
211
|
expect(block).toContain('return 5;');
|
|
@@ -223,7 +223,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
223
223
|
' int value_;',
|
|
224
224
|
'};',
|
|
225
225
|
].join('\n');
|
|
226
|
-
(readFileSync as
|
|
226
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
227
227
|
const adapter = new CppAdapter('test.cpp');
|
|
228
228
|
const functions = adapter.extractFunctions();
|
|
229
229
|
expect(Array.isArray(functions)).toBe(true);
|
|
@@ -240,7 +240,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
240
240
|
' int x;',
|
|
241
241
|
'};',
|
|
242
242
|
].join('\n');
|
|
243
|
-
(readFileSync as
|
|
243
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
244
244
|
const adapter = new CppAdapter('test.cpp');
|
|
245
245
|
const classes = adapter.extractClasses();
|
|
246
246
|
expect(Array.isArray(classes)).toBe(true);
|
|
@@ -250,13 +250,13 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
250
250
|
});
|
|
251
251
|
|
|
252
252
|
it('should count lines correctly', () => {
|
|
253
|
-
(readFileSync as
|
|
253
|
+
(readFileSync as Mock).mockReturnValue('line1\nline2\nline3');
|
|
254
254
|
const adapter = new CppAdapter('test.cpp');
|
|
255
255
|
expect(adapter.countLines()).toBe(3);
|
|
256
256
|
});
|
|
257
257
|
|
|
258
258
|
it('should fall back to super.detectLanguage for non-cpp extensions', () => {
|
|
259
|
-
(readFileSync as
|
|
259
|
+
(readFileSync as Mock).mockReturnValue('content');
|
|
260
260
|
const adapter = new CppAdapter('test.txt');
|
|
261
261
|
expect(adapter.detectLanguage()).toBe('unknown');
|
|
262
262
|
});
|
|
@@ -272,7 +272,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
272
272
|
' return -x;',
|
|
273
273
|
'}',
|
|
274
274
|
].join('\n');
|
|
275
|
-
(readFileSync as
|
|
275
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
276
276
|
const adapter = new CppAdapter('test.cpp');
|
|
277
277
|
const functions = adapter.extractFunctions();
|
|
278
278
|
expect(Array.isArray(functions)).toBe(true);
|
|
@@ -281,7 +281,7 @@ describe('CppAdapter - extractCodeBlock edge cases', () => {
|
|
|
281
281
|
|
|
282
282
|
it('should extract functions with scope prefix (e.g. MyClass::method)', () => {
|
|
283
283
|
const src = 'void MyClass::method() { return; }';
|
|
284
|
-
(readFileSync as
|
|
284
|
+
(readFileSync as Mock).mockReturnValue(src);
|
|
285
285
|
const adapter = new CppAdapter('test.cpp');
|
|
286
286
|
const functions = adapter.extractFunctions();
|
|
287
287
|
expect(Array.isArray(functions)).toBe(true);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
1
|
+
import { describe, it, expect, vi, type Mock } from 'vitest';;
|
|
2
2
|
import { DartAdapter } from '../dart';
|
|
3
3
|
|
|
4
4
|
vi.mock('fs', () => ({
|
|
@@ -10,7 +10,7 @@ import { readFileSync } from 'fs';
|
|
|
10
10
|
|
|
11
11
|
describe('DartAdapter', () => {
|
|
12
12
|
it('should implement the Adapter interface', () => {
|
|
13
|
-
(readFileSync as
|
|
13
|
+
(readFileSync as Mock).mockReturnValue('void testFn() {}\nclass TestClass {}');
|
|
14
14
|
const adapter = new DartAdapter('test.dart');
|
|
15
15
|
|
|
16
16
|
expect(adapter).toHaveProperty('detectLanguage');
|
|
@@ -21,24 +21,24 @@ describe('DartAdapter', () => {
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('should detect language as dart for .dart files', () => {
|
|
24
|
-
(readFileSync as
|
|
24
|
+
(readFileSync as Mock).mockReturnValue('void testFn() {}');
|
|
25
25
|
const adapter = new DartAdapter('test.dart');
|
|
26
26
|
const detected = adapter.detectLanguage();
|
|
27
27
|
expect(detected).toBe('dart');
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
it('should parse Dart file AST correctly', () => {
|
|
31
|
-
(readFileSync as
|
|
31
|
+
(readFileSync as Mock).mockReturnValue('void testFn() {}\nclass TestClass {}');
|
|
32
32
|
const adapter = new DartAdapter('test.dart');
|
|
33
33
|
const ast = adapter.parseAST();
|
|
34
34
|
expect(ast).toHaveProperty('content');
|
|
35
35
|
expect(ast).toHaveProperty('language');
|
|
36
36
|
expect(ast).toHaveProperty('filePath');
|
|
37
|
-
expect(ast.language).toBe('dart');
|
|
37
|
+
expect((ast as { language: unknown }).language).toBe('dart');
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it('should extract functions from Dart AST', () => {
|
|
41
|
-
(readFileSync as
|
|
41
|
+
(readFileSync as Mock).mockReturnValue('void testFn() {}\nclass TestClass {}');
|
|
42
42
|
const adapter = new DartAdapter('test.dart');
|
|
43
43
|
const functions = adapter.extractFunctions();
|
|
44
44
|
expect(Array.isArray(functions)).toBe(true);
|
|
@@ -46,7 +46,7 @@ describe('DartAdapter', () => {
|
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
it('should extract classes from Dart AST', () => {
|
|
49
|
-
(readFileSync as
|
|
49
|
+
(readFileSync as Mock).mockReturnValue('void testFn() {}\nclass TestClass {}');
|
|
50
50
|
const adapter = new DartAdapter('test.dart');
|
|
51
51
|
const classes = adapter.extractClasses();
|
|
52
52
|
expect(Array.isArray(classes)).toBe(true);
|
|
@@ -54,20 +54,20 @@ describe('DartAdapter', () => {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
it('should count Dart file physical lines', () => {
|
|
57
|
-
(readFileSync as
|
|
57
|
+
(readFileSync as Mock).mockReturnValue('void testFn() {}\nvoid testFn2() {}');
|
|
58
58
|
const adapter = new DartAdapter('test.dart');
|
|
59
59
|
const lineCount = adapter.countLines();
|
|
60
60
|
expect(lineCount).toBe(2);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
it('should fall back to super.detectLanguage for non-dart extensions', () => {
|
|
64
|
-
(readFileSync as
|
|
64
|
+
(readFileSync as Mock).mockReturnValue('content');
|
|
65
65
|
const adapter = new DartAdapter('test.py');
|
|
66
66
|
expect(adapter.detectLanguage()).toBe('python');
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
it('should handle async functions in Dart', () => {
|
|
70
|
-
(readFileSync as
|
|
70
|
+
(readFileSync as Mock).mockReturnValue('Future<void> fetchData() async {}\nasync void fireAndForget() {}');
|
|
71
71
|
const adapter = new DartAdapter('test.dart');
|
|
72
72
|
const functions = adapter.extractFunctions();
|
|
73
73
|
const asyncFns = functions.filter(fn => (fn as {type: string}).type === 'async_function');
|
|
@@ -75,7 +75,7 @@ describe('DartAdapter', () => {
|
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
it('should handle abstract class declarations in Dart', () => {
|
|
78
|
-
(readFileSync as
|
|
78
|
+
(readFileSync as Mock).mockReturnValue('abstract class Repository {\n void save();\n}\n');
|
|
79
79
|
const adapter = new DartAdapter('test.dart');
|
|
80
80
|
const classes = adapter.extractClasses();
|
|
81
81
|
const abstractClasses = classes.filter(cls => (cls as {type: string}).type === 'abstract_class');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
1
|
+
import { describe, it, expect, vi, type Mock } from 'vitest';;
|
|
2
2
|
import { GoAdapter } from '../go';
|
|
3
3
|
|
|
4
4
|
vi.mock('fs', () => ({
|
|
@@ -10,7 +10,7 @@ import { readFileSync } from 'fs';
|
|
|
10
10
|
|
|
11
11
|
describe('GoAdapter', () => {
|
|
12
12
|
it('should implement the Adapter interface', () => {
|
|
13
|
-
(readFileSync as
|
|
13
|
+
(readFileSync as Mock).mockReturnValue('func testFn() {}\ntype TestClass struct {}');
|
|
14
14
|
const adapter = new GoAdapter('test.go');
|
|
15
15
|
|
|
16
16
|
expect(adapter).toHaveProperty('detectLanguage');
|
|
@@ -21,24 +21,24 @@ describe('GoAdapter', () => {
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('should detect language as go for .go files', () => {
|
|
24
|
-
(readFileSync as
|
|
24
|
+
(readFileSync as Mock).mockReturnValue('func testFn() {}');
|
|
25
25
|
const adapter = new GoAdapter('test.go');
|
|
26
26
|
const detected = adapter.detectLanguage();
|
|
27
27
|
expect(detected).toBe('go');
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
it('should parse Go file AST correctly', () => {
|
|
31
|
-
(readFileSync as
|
|
31
|
+
(readFileSync as Mock).mockReturnValue('func testFn() {}\ntype TestClass struct {}');
|
|
32
32
|
const adapter = new GoAdapter('test.go');
|
|
33
33
|
const ast = adapter.parseAST();
|
|
34
34
|
expect(ast).toHaveProperty('content');
|
|
35
35
|
expect(ast).toHaveProperty('language');
|
|
36
36
|
expect(ast).toHaveProperty('filePath');
|
|
37
|
-
expect(ast.language).toBe('go');
|
|
37
|
+
expect((ast as { language: unknown }).language).toBe('go');
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it('should extract functions from Go AST', () => {
|
|
41
|
-
(readFileSync as
|
|
41
|
+
(readFileSync as Mock).mockReturnValue('func testFn() {}\nfunc (t *TestClass) method() {}');
|
|
42
42
|
const adapter = new GoAdapter('test.go');
|
|
43
43
|
const functions = adapter.extractFunctions();
|
|
44
44
|
expect(Array.isArray(functions)).toBe(true);
|
|
@@ -46,7 +46,7 @@ describe('GoAdapter', () => {
|
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
it('should extract structs from Go AST', () => {
|
|
49
|
-
(readFileSync as
|
|
49
|
+
(readFileSync as Mock).mockReturnValue('func testFn() {}\ntype TestClass struct {}');
|
|
50
50
|
const adapter = new GoAdapter('test.go');
|
|
51
51
|
const classes = adapter.extractClasses();
|
|
52
52
|
expect(Array.isArray(classes)).toBe(true);
|
|
@@ -54,14 +54,14 @@ describe('GoAdapter', () => {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
it('should count Go file physical lines', () => {
|
|
57
|
-
(readFileSync as
|
|
57
|
+
(readFileSync as Mock).mockReturnValue('func testFn() {}\nfunc testFn2() {}');
|
|
58
58
|
const adapter = new GoAdapter('test.go');
|
|
59
59
|
const lineCount = adapter.countLines();
|
|
60
60
|
expect(lineCount).toBe(2);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
it('should fall back to super.detectLanguage for non-go extensions', () => {
|
|
64
|
-
(readFileSync as
|
|
64
|
+
(readFileSync as Mock).mockReturnValue('content');
|
|
65
65
|
const adapter = new GoAdapter('test.ts');
|
|
66
66
|
expect(adapter.detectLanguage()).toBe('typescript');
|
|
67
67
|
});
|