@boyingliu01/xp-gate 0.8.9 → 0.8.10

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 (132) hide show
  1. package/lib/init.js +36 -0
  2. package/mock-policy/AGENTS.md +94 -0
  3. package/mock-policy/__tests__/config.test.ts +292 -0
  4. package/mock-policy/__tests__/integration.test.ts +600 -0
  5. package/mock-policy/__tests__/mock-decision-engine.test.ts +231 -0
  6. package/mock-policy/__tests__/scope-scanner.test.ts +535 -0
  7. package/mock-policy/config.ts +106 -0
  8. package/mock-policy/gate-m3.ts +233 -0
  9. package/mock-policy/mock-decision-engine.ts +155 -0
  10. package/mock-policy/schema.ts +22 -0
  11. package/mock-policy/scope-scanner.ts +288 -0
  12. package/mock-policy/types.ts +65 -0
  13. package/mutation/AGENTS.md +73 -0
  14. package/mutation/__tests__/detect-ai-test.test.ts +152 -0
  15. package/mutation/__tests__/gate-m.test.ts +194 -0
  16. package/mutation/detect-ai-test.ts +128 -0
  17. package/mutation/gate-m.ts +619 -0
  18. package/mutation/init-baseline.ts +192 -0
  19. package/mutation/stryker-types.ts +14 -0
  20. package/mutation/types.ts +70 -0
  21. package/mutation/update-baseline.ts +160 -0
  22. package/package.json +5 -2
  23. package/plugins/claude-code/.claude-plugin/plugin.json +2 -2
  24. package/plugins/claude-code/skills/delphi-review/AGENTS.md +7 -7
  25. package/plugins/claude-code/skills/delphi-review/INSTALL.md +1 -1
  26. package/plugins/claude-code/skills/delphi-review/SKILL.md +12 -12
  27. package/plugins/claude-code/skills/delphi-review/references/code-walkthrough.md +1 -1
  28. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +7 -7
  29. package/plugins/claude-code/skills/sprint-flow/SKILL.md +1 -1
  30. package/plugins/claude-code/skills/sprint-flow/references/force-levels.md +1 -1
  31. package/plugins/claude-code/skills/sprint-flow/references/phase-3-review.md +2 -2
  32. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +3 -3
  33. package/plugins/opencode/package.json +1 -1
  34. package/plugins/opencode/skills/delphi-review/AGENTS.md +7 -7
  35. package/plugins/opencode/skills/delphi-review/INSTALL.md +1 -1
  36. package/plugins/opencode/skills/delphi-review/SKILL.md +12 -12
  37. package/plugins/opencode/skills/delphi-review/references/code-walkthrough.md +1 -1
  38. package/plugins/opencode/skills/sprint-flow/AGENTS.md +7 -7
  39. package/plugins/opencode/skills/sprint-flow/SKILL.md +1 -1
  40. package/plugins/opencode/skills/sprint-flow/references/force-levels.md +1 -1
  41. package/plugins/opencode/skills/sprint-flow/references/phase-3-review.md +2 -2
  42. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +3 -3
  43. package/plugins/qoder/plugin.json +1 -1
  44. package/plugins/qoder/skills/delphi-review/AGENTS.md +7 -7
  45. package/plugins/qoder/skills/delphi-review/INSTALL.md +1 -1
  46. package/plugins/qoder/skills/delphi-review/SKILL.md +12 -12
  47. package/plugins/qoder/skills/delphi-review/references/code-walkthrough.md +1 -1
  48. package/plugins/qoder/skills/sprint-flow/AGENTS.md +7 -7
  49. package/plugins/qoder/skills/sprint-flow/SKILL.md +51 -1
  50. package/plugins/qoder/skills/sprint-flow/references/force-levels.md +1 -1
  51. package/plugins/qoder/skills/sprint-flow/references/phase-3-review.md +2 -2
  52. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +3 -3
  53. package/principles/AGENTS.md +111 -0
  54. package/principles/__tests__/analyzer.test.ts +343 -0
  55. package/principles/__tests__/baseline-storage.test.ts +187 -0
  56. package/principles/__tests__/baseline.test.ts +328 -0
  57. package/principles/__tests__/boy-scout-integration.test.ts +264 -0
  58. package/principles/__tests__/boy-scout.test.ts +646 -0
  59. package/principles/__tests__/config.test.ts +78 -0
  60. package/principles/__tests__/index.test.ts +81 -0
  61. package/principles/__tests__/lint-baseline.test.ts +314 -0
  62. package/principles/__tests__/reporter.test.ts +832 -0
  63. package/principles/__tests__/types.test.ts +101 -0
  64. package/principles/adapters/__tests__/base.test.ts +95 -0
  65. package/principles/adapters/__tests__/cpp.test.ts +290 -0
  66. package/principles/adapters/__tests__/dart.test.ts +84 -0
  67. package/principles/adapters/__tests__/go.test.ts +68 -0
  68. package/principles/adapters/__tests__/java.test.ts +68 -0
  69. package/principles/adapters/__tests__/kotlin.test.ts +76 -0
  70. package/principles/adapters/__tests__/objectivec.test.ts +453 -0
  71. package/principles/adapters/__tests__/python.test.ts +84 -0
  72. package/principles/adapters/__tests__/swift.test.ts +68 -0
  73. package/principles/adapters/__tests__/typescript.test.ts +116 -0
  74. package/principles/adapters/base.ts +124 -0
  75. package/principles/adapters/cpp.ts +115 -0
  76. package/principles/adapters/dart.ts +44 -0
  77. package/principles/adapters/go.ts +55 -0
  78. package/principles/adapters/java.ts +56 -0
  79. package/principles/adapters/kotlin.ts +54 -0
  80. package/principles/adapters/objectivec.ts +82 -0
  81. package/principles/adapters/python.ts +83 -0
  82. package/principles/adapters/swift.ts +40 -0
  83. package/principles/adapters/typescript.ts +66 -0
  84. package/principles/analyzer.ts +190 -0
  85. package/principles/baseline.ts +273 -0
  86. package/principles/boy-scout.ts +416 -0
  87. package/principles/config.ts +118 -0
  88. package/principles/index.ts +87 -0
  89. package/principles/lint-baseline.ts +385 -0
  90. package/principles/reporter.ts +188 -0
  91. package/principles/rules/__tests__/clean-code/code-duplication.test.ts +84 -0
  92. package/principles/rules/__tests__/clean-code/deep-nesting.test.ts +74 -0
  93. package/principles/rules/__tests__/clean-code/god-class.test.ts +111 -0
  94. package/principles/rules/__tests__/clean-code/large-file.test.ts +73 -0
  95. package/principles/rules/__tests__/clean-code/long-function.test.ts +83 -0
  96. package/principles/rules/__tests__/clean-code/magic-numbers.test.ts +68 -0
  97. package/principles/rules/__tests__/clean-code/many-exports.test.ts +118 -0
  98. package/principles/rules/__tests__/clean-code/missing-error-handling.test.ts +173 -0
  99. package/principles/rules/__tests__/clean-code/too-many-params.test.ts +60 -0
  100. package/principles/rules/__tests__/clean-code/unused-imports.test.ts +107 -0
  101. package/principles/rules/__tests__/index.test.ts +49 -0
  102. package/principles/rules/__tests__/solid/dip.test.ts +121 -0
  103. package/principles/rules/__tests__/solid/isp.test.ts +60 -0
  104. package/principles/rules/__tests__/solid/lsp.test.ts +184 -0
  105. package/principles/rules/__tests__/solid/ocp.test.ts +69 -0
  106. package/principles/rules/__tests__/solid/srp.test.ts +89 -0
  107. package/principles/rules/clean-code/code-duplication.ts +31 -0
  108. package/principles/rules/clean-code/deep-nesting.ts +38 -0
  109. package/principles/rules/clean-code/god-class.ts +54 -0
  110. package/principles/rules/clean-code/large-file.ts +34 -0
  111. package/principles/rules/clean-code/long-function.ts +47 -0
  112. package/principles/rules/clean-code/magic-numbers.ts +59 -0
  113. package/principles/rules/clean-code/many-exports.ts +40 -0
  114. package/principles/rules/clean-code/missing-error-handling.ts +33 -0
  115. package/principles/rules/clean-code/too-many-params.ts +35 -0
  116. package/principles/rules/clean-code/unused-imports.ts +33 -0
  117. package/principles/rules/index.ts +61 -0
  118. package/principles/rules/solid/dip.ts +47 -0
  119. package/principles/rules/solid/isp.ts +37 -0
  120. package/principles/rules/solid/lsp.ts +79 -0
  121. package/principles/rules/solid/ocp.ts +40 -0
  122. package/principles/rules/solid/srp.ts +44 -0
  123. package/principles/types.ts +27 -0
  124. package/skills/delphi-review/AGENTS.md +7 -7
  125. package/skills/delphi-review/INSTALL.md +1 -1
  126. package/skills/delphi-review/SKILL.md +12 -12
  127. package/skills/delphi-review/references/code-walkthrough.md +1 -1
  128. package/skills/sprint-flow/AGENTS.md +7 -7
  129. package/skills/sprint-flow/SKILL.md +1 -1
  130. package/skills/sprint-flow/references/force-levels.md +1 -1
  131. package/skills/sprint-flow/references/phase-3-review.md +2 -2
  132. package/skills/test-specification-alignment/AGENTS.md +3 -3
@@ -0,0 +1,68 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { SwiftAdapter } from '../swift';
3
+
4
+ vi.mock('fs', () => ({
5
+ readFileSync: vi.fn(),
6
+ existsSync: vi.fn(() => true),
7
+ }));
8
+
9
+ import { readFileSync } from 'fs';
10
+
11
+ describe('SwiftAdapter', () => {
12
+ it('should implement the Adapter interface', () => {
13
+ (readFileSync as vi.Mock).mockReturnValue('func testFn() {}\nclass TestClass {}');
14
+ const adapter = new SwiftAdapter('test.swift');
15
+
16
+ expect(adapter).toHaveProperty('detectLanguage');
17
+ expect(adapter).toHaveProperty('parseAST');
18
+ expect(adapter).toHaveProperty('extractFunctions');
19
+ expect(adapter).toHaveProperty('extractClasses');
20
+ expect(adapter).toHaveProperty('countLines');
21
+ });
22
+
23
+ it('should detect language as swift for .swift files', () => {
24
+ (readFileSync as vi.Mock).mockReturnValue('func testFn() {}');
25
+ const adapter = new SwiftAdapter('test.swift');
26
+ const detected = adapter.detectLanguage();
27
+ expect(detected).toBe('swift');
28
+ });
29
+
30
+ it('should parse Swift file AST correctly', () => {
31
+ (readFileSync as vi.Mock).mockReturnValue('func testFn() {}\nclass TestClass {}');
32
+ const adapter = new SwiftAdapter('test.swift');
33
+ const ast = adapter.parseAST();
34
+ expect(ast).toHaveProperty('content');
35
+ expect(ast).toHaveProperty('language');
36
+ expect(ast).toHaveProperty('filePath');
37
+ expect(ast.language).toBe('swift');
38
+ });
39
+
40
+ it('should extract functions from Swift AST', () => {
41
+ (readFileSync as vi.Mock).mockReturnValue('func testFn() {}\nclass TestClass {}');
42
+ const adapter = new SwiftAdapter('test.swift');
43
+ const functions = adapter.extractFunctions();
44
+ expect(Array.isArray(functions)).toBe(true);
45
+ expect(functions.some(fn => (fn as {name: string}).name === 'testFn')).toBe(true);
46
+ });
47
+
48
+ it('should extract classes from Swift AST', () => {
49
+ (readFileSync as vi.Mock).mockReturnValue('func testFn() {}\nclass TestClass {}');
50
+ const adapter = new SwiftAdapter('test.swift');
51
+ const classes = adapter.extractClasses();
52
+ expect(Array.isArray(classes)).toBe(true);
53
+ expect(classes.some(cls => (cls as {name: string}).name === 'TestClass')).toBe(true);
54
+ });
55
+
56
+ it('should count Swift file physical lines', () => {
57
+ (readFileSync as vi.Mock).mockReturnValue('func testFn() {}\nfunc testFn2() {}');
58
+ const adapter = new SwiftAdapter('test.swift');
59
+ const lineCount = adapter.countLines();
60
+ expect(lineCount).toBe(2);
61
+ });
62
+
63
+ it('should fall back to super.detectLanguage for non-swift extensions', () => {
64
+ (readFileSync as vi.Mock).mockReturnValue('content');
65
+ const adapter = new SwiftAdapter('test.py');
66
+ expect(adapter.detectLanguage()).toBe('python');
67
+ });
68
+ });
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { TypeScriptAdapter } from '../typescript';
3
+
4
+ vi.mock('fs', () => ({
5
+ readFileSync: vi.fn(),
6
+ existsSync: vi.fn(() => true),
7
+ }));
8
+
9
+ import { readFileSync } from 'fs';
10
+
11
+ describe('TypeScriptAdapter', () => {
12
+
13
+ it('should implement the Adapter interface', () => {
14
+ (readFileSync as vi.Mock).mockReturnValue('export function testFn() {}\nclass TestClass {}');
15
+ const adapter = new TypeScriptAdapter('test.ts');
16
+
17
+ expect(adapter).toHaveProperty('detectLanguage');
18
+ expect(adapter).toHaveProperty('parseAST');
19
+ expect(adapter).toHaveProperty('extractFunctions');
20
+ expect(adapter).toHaveProperty('extractClasses');
21
+ expect(adapter).toHaveProperty('countLines');
22
+ });
23
+
24
+ it('should detect language as typescript for .ts files', () => {
25
+ (readFileSync as vi.Mock).mockReturnValue('export function testFn() {}\nclass TestClass {}');
26
+ const adapter = new TypeScriptAdapter('test.ts');
27
+ const detected = adapter.detectLanguage();
28
+ expect(detected).toBe('typescript');
29
+ });
30
+
31
+ it('should detect language as typescript for .tsx files', () => {
32
+ (readFileSync as vi.Mock).mockReturnValue('export function testFn() {}\nclass TestClass {}');
33
+ const adapter = new TypeScriptAdapter('test.tsx');
34
+ const detected = adapter.detectLanguage();
35
+ expect(detected).toBe('typescript');
36
+ });
37
+
38
+ it('should parse TypeScript file AST correctly', () => {
39
+ (readFileSync as vi.Mock).mockReturnValue('export function testFn() {}\nclass TestClass {}');
40
+ const adapter = new TypeScriptAdapter('test.ts');
41
+ const ast = adapter.parseAST();
42
+ expect(ast).toHaveProperty('content');
43
+ expect(ast).toHaveProperty('language');
44
+ expect(ast).toHaveProperty('filePath');
45
+ expect(ast.language).toBe('typescript');
46
+ });
47
+
48
+ it('should extract functions from TypeScript AST', () => {
49
+ (readFileSync as vi.Mock).mockReturnValue('export function testFn() {}\nclass TestClass {}');
50
+ const adapter = new TypeScriptAdapter('test.ts');
51
+ const functions = adapter.extractFunctions();
52
+ expect(Array.isArray(functions)).toBe(true);
53
+ expect(functions.some(fn => (fn as {name: string}).name === 'testFn')).toBe(true);
54
+ });
55
+
56
+ it('should extract classes from TypeScript AST', () => {
57
+ (readFileSync as vi.Mock).mockReturnValue('export function testFn() {}\nclass TestClass {}');
58
+ const adapter = new TypeScriptAdapter('test.ts');
59
+ const classes = adapter.extractClasses();
60
+ expect(Array.isArray(classes)).toBe(true);
61
+ expect(classes.some(cls => (cls as {name: string}).name === 'TestClass')).toBe(true);
62
+ });
63
+
64
+ it('should count TypeScript file physical lines', () => {
65
+ (readFileSync as vi.Mock).mockReturnValue('export function testFn() {}\nexport function testFn2() {}');
66
+ const adapter = new TypeScriptAdapter('test.ts');
67
+ const lineCount = adapter.countLines();
68
+ expect(lineCount).toBe(2);
69
+ });
70
+
71
+ it('should handle TypeScript-specific syntax correctly', () => {
72
+ (readFileSync as vi.Mock).mockReturnValue(`
73
+ export async function asyncFn() {}
74
+ export function* generatorFn() {}
75
+ class MyClass {
76
+ method() {}
77
+ }
78
+ interface MyInterface {}
79
+ type MyType = string;
80
+ `);
81
+
82
+ const adapter = new TypeScriptAdapter('test.ts');
83
+
84
+ const functions = adapter.extractFunctions();
85
+ expect(Array.isArray(functions)).toBe(true);
86
+
87
+ const classes = adapter.extractClasses();
88
+ expect(Array.isArray(classes)).toBe(true);
89
+
90
+ expect(adapter.detectLanguage()).toBe('typescript');
91
+ });
92
+
93
+ it('should throw error when file cannot be read', () => {
94
+ (readFileSync as vi.Mock).mockImplementation(() => {
95
+ throw new Error('Could not read file');
96
+ });
97
+
98
+ expect(() => {
99
+ new TypeScriptAdapter('nonexistent-file.ts');
100
+ }).toThrow('Could not read file:');
101
+ });
102
+
103
+ it('should fall back to super.detectLanguage for non-ts/non-tsx extensions', () => {
104
+ (readFileSync as vi.Mock).mockReturnValue('content');
105
+ const adapter = new TypeScriptAdapter('test.py');
106
+ expect(adapter.detectLanguage()).toBe('python');
107
+ });
108
+
109
+ it('should extract re-export declarations', () => {
110
+ (readFileSync as vi.Mock).mockReturnValue('export { Foo };\nexport { Bar };\nexport function baz() {}');
111
+ const adapter = new TypeScriptAdapter('test.ts');
112
+ const exports = adapter.extractExports();
113
+ const reExports = exports.filter(ex => (ex as {type: string}).type === 're-export');
114
+ expect(reExports.length).toBe(2);
115
+ });
116
+ });
@@ -0,0 +1,124 @@
1
+ import { readFileSync } from 'fs';
2
+ import { extname } from 'path';
3
+ import { Adapter } from '../types';
4
+
5
+ export abstract class BaseAdapter implements Adapter {
6
+ protected readonly filePath: string;
7
+ protected readonly fileContent: string;
8
+
9
+ constructor(filePath: string) {
10
+ this.filePath = filePath;
11
+ this.fileContent = this.readFileContent(filePath);
12
+ }
13
+
14
+ detectLanguage(): string {
15
+ const extension = extname(this.filePath).toLowerCase();
16
+
17
+ const languageMap: Record<string, string> = {
18
+ '.ts': 'typescript',
19
+ '.tsx': 'typescript',
20
+ '.js': 'javascript',
21
+ '.jsx': 'javascript',
22
+ '.py': 'python',
23
+ '.go': 'go',
24
+ '.java': 'java',
25
+ '.kt': 'kotlin',
26
+ '.dart': 'dart',
27
+ '.swift': 'swift',
28
+ };
29
+
30
+ return languageMap[extension] || 'unknown';
31
+ }
32
+
33
+ abstract parseAST(): unknown;
34
+ abstract extractFunctions(): unknown[];
35
+ abstract extractClasses(): unknown[];
36
+
37
+ extractExports(): unknown[] {
38
+ return [];
39
+ }
40
+
41
+ protected createParseResult(language: string): unknown {
42
+ return {
43
+ content: this.fileContent,
44
+ language,
45
+ filePath: this.filePath,
46
+ };
47
+ }
48
+
49
+ protected createCodeMatch(name: string, type: string, index: number): unknown {
50
+ return {
51
+ name,
52
+ type,
53
+ line: this.getLineNumber(index),
54
+ code: this.extractCodeBlock(index),
55
+ };
56
+ }
57
+
58
+ countLines(): number {
59
+ return this.fileContent.split('\n').length;
60
+ }
61
+
62
+ protected readFileContent(filePath: string): string {
63
+ try {
64
+ return readFileSync(filePath, 'utf-8');
65
+ } catch {
66
+ throw new Error(`Could not read file: ${filePath}`);
67
+ }
68
+ }
69
+
70
+ protected getLineNumber(position: number): number {
71
+ return this.fileContent.substring(0, position).split('\n').length;
72
+ }
73
+
74
+ protected fallbackCodeBlock(startPos: number, maxFallback: number): string {
75
+ const code = this.fileContent.substring(startPos);
76
+ return code.substring(0, Math.min(maxFallback, code.length));
77
+ }
78
+
79
+ /**
80
+ * Advance brace tracker by one character. Returns updated state and signals when
81
+ * a balanced block closes so callers can break out of their scan loop.
82
+ */
83
+ protected advanceBraceTracker(
84
+ char: string,
85
+ index: number,
86
+ state: { inBlock: boolean; braceCount: number },
87
+ ): { closed: boolean; endPos: number } {
88
+ if (char === '{' && !state.inBlock) {
89
+ state.inBlock = true;
90
+ state.braceCount = 1;
91
+ return { closed: false, endPos: index };
92
+ }
93
+ if (char === '{' && state.inBlock) {
94
+ state.braceCount += 1;
95
+ return { closed: false, endPos: index };
96
+ }
97
+ if (char === '}' && state.inBlock) {
98
+ state.braceCount -= 1;
99
+ if (state.braceCount === 0) {
100
+ return { closed: true, endPos: index + 1 };
101
+ }
102
+ }
103
+ return { closed: false, endPos: index };
104
+ }
105
+
106
+ protected extractCodeBlock(startPos: number, maxFallback: number = 100): string {
107
+ const state = { inBlock: false, braceCount: 0 };
108
+ let endPos = startPos;
109
+
110
+ for (let i = startPos; i < this.fileContent.length; i++) {
111
+ const result = this.advanceBraceTracker(this.fileContent[i], i, state);
112
+ if (result.closed) {
113
+ endPos = result.endPos;
114
+ break;
115
+ }
116
+ }
117
+
118
+ if (endPos > startPos) {
119
+ return this.fileContent.substring(startPos, endPos);
120
+ }
121
+
122
+ return this.fallbackCodeBlock(startPos, maxFallback);
123
+ }
124
+ }
@@ -0,0 +1,115 @@
1
+ import { BaseAdapter } from './base';
2
+ import { Adapter } from '../types';
3
+
4
+ export class CppAdapter extends BaseAdapter implements Adapter {
5
+ detectLanguage(): string {
6
+ const ext = this.filePath.toLowerCase();
7
+ if (ext.endsWith('.cpp') || ext.endsWith('.cxx') || ext.endsWith('.cc') ||
8
+ ext.endsWith('.c') || ext.endsWith('.hpp') || ext.endsWith('.h')) {
9
+ return 'cpp';
10
+ }
11
+ return super.detectLanguage();
12
+ }
13
+
14
+ parseAST(): unknown {
15
+ return this.createParseResult('cpp');
16
+ }
17
+
18
+ extractFunctions(): unknown[] {
19
+ const functionMatches = [];
20
+ const fnRegex = /(\w+[\s*]+)+([\w:]+[:]+)?([~]?\w+)\s*\([^)]*\)\s*(const\s*)?\s*(override\s*)?\s*(final\s*)?\s*(noexcept\s*)?\s*(->\s*[\w<>:&*\s]+)?\s*[{;]/g;
21
+ let match;
22
+
23
+ while ((match = fnRegex.exec(this.fileContent)) !== null) {
24
+ const funcName = match[3] || 'unknown';
25
+ const fullName = match[2] ? match[2] + funcName : funcName;
26
+
27
+ functionMatches.push(this.createCodeMatch(fullName.replace(/::$/, ''), 'function', match.index));
28
+ }
29
+
30
+ const constructorRegex = /([\w:]+)\s*\([^)]*\)\s*:\s*[\w_]+\s*\([^)]*\)/g;
31
+ while ((match = constructorRegex.exec(this.fileContent)) !== null) {
32
+ const constructorName = match[1];
33
+
34
+ functionMatches.push(this.createCodeMatch(constructorName, 'constructor', match.index));
35
+ }
36
+
37
+ return functionMatches;
38
+ }
39
+
40
+ extractClasses(): unknown[] {
41
+ const classMatches = [];
42
+ const classRegex = /\b(class|struct)\s+(\w+)\s*(:\s*(public|protected|private)\s+[\w:]+)?\s*\{/g;
43
+ let match;
44
+
45
+ while ((match = classRegex.exec(this.fileContent)) !== null) {
46
+ classMatches.push(this.createCodeMatch(match[2], match[1], match.index));
47
+ }
48
+
49
+ return classMatches;
50
+ }
51
+
52
+ override extractCodeBlock(startPos: number, maxFallback: number = 200): string {
53
+ const state = { inBlock: false, braceCount: 0 };
54
+ let endPos = startPos;
55
+ let inString = false;
56
+ let stringChar = '';
57
+ let inComment = false;
58
+
59
+ for (let i = startPos; i < this.fileContent.length; i++) {
60
+ const char = this.fileContent[i];
61
+ const nextChar = this.fileContent[i + 1] || '';
62
+
63
+ if (!inString && !inComment) {
64
+ if (char === '/' && nextChar === '/') {
65
+ while (i < this.fileContent.length && this.fileContent[i] !== '\n') {
66
+ i++;
67
+ }
68
+ continue;
69
+ }
70
+ if (char === '/' && nextChar === '*') {
71
+ inComment = true;
72
+ i++;
73
+ continue;
74
+ }
75
+ } else if (inComment) {
76
+ if (char === '*' && nextChar === '/') {
77
+ inComment = false;
78
+ i++;
79
+ }
80
+ continue;
81
+ }
82
+
83
+ if (!inComment) {
84
+ if (!inString && (char === '"' || char === "'")) {
85
+ inString = true;
86
+ stringChar = char;
87
+ } else if (inString && char === stringChar) {
88
+ let backslashCount = 0;
89
+ let j = i - 1;
90
+ while (j >= 0 && this.fileContent[j] === '\\') {
91
+ backslashCount++;
92
+ j--;
93
+ }
94
+ if (backslashCount % 2 === 0) {
95
+ inString = false;
96
+ }
97
+ }
98
+ }
99
+
100
+ if (!inString && !inComment) {
101
+ const result = this.advanceBraceTracker(char, i, state);
102
+ if (result.closed) {
103
+ endPos = result.endPos;
104
+ break;
105
+ }
106
+ }
107
+ }
108
+
109
+ if (endPos > startPos) {
110
+ return this.fileContent.substring(startPos, endPos);
111
+ }
112
+
113
+ return this.fallbackCodeBlock(startPos, maxFallback);
114
+ }
115
+ }
@@ -0,0 +1,44 @@
1
+ import { BaseAdapter } from './base';
2
+ import { Adapter } from '../types';
3
+
4
+ export class DartAdapter extends BaseAdapter implements Adapter {
5
+ detectLanguage(): string {
6
+ const ext = this.filePath.toLowerCase();
7
+ if (ext.endsWith('.dart')) {
8
+ return 'dart';
9
+ }
10
+ return super.detectLanguage();
11
+ }
12
+
13
+ parseAST(): unknown {
14
+ return this.createParseResult('dart');
15
+ }
16
+
17
+ extractFunctions(): unknown[] {
18
+ const functionMatches = [];
19
+ const fnRegex = /(async\s+)?[\w<>]+\s+(\w+)\s*\([^)]*\)\s*(async\s*)?\s*{/g;
20
+ let match;
21
+
22
+ while ((match = fnRegex.exec(this.fileContent)) !== null) {
23
+ if (match[2] !== 'class' && match[2] !== 'interface' && match[2] !== 'abstract') {
24
+ const type = match[1] ? 'async_function' : 'function';
25
+ functionMatches.push(this.createCodeMatch(match[2], type, match.index));
26
+ }
27
+ }
28
+
29
+ return functionMatches;
30
+ }
31
+
32
+ extractClasses(): unknown[] {
33
+ const classMatches = [];
34
+ const classRegex = /(abstract\s+)?class\s+(\w+)\s*(extends\s+\w+)?\s*(with\s+[\w,\s]+)?\s*(implements\s+[\w,\s]+)?\s*{/g;
35
+ let match;
36
+
37
+ while ((match = classRegex.exec(this.fileContent)) !== null) {
38
+ const type = match[1] ? 'abstract_class' : 'class';
39
+ classMatches.push(this.createCodeMatch(match[2], type, match.index));
40
+ }
41
+
42
+ return classMatches;
43
+ }
44
+ }
@@ -0,0 +1,55 @@
1
+ import { BaseAdapter } from './base';
2
+ import { Adapter } from '../types';
3
+
4
+ export class GoAdapter extends BaseAdapter implements Adapter {
5
+ detectLanguage(): string {
6
+ const ext = this.filePath.toLowerCase();
7
+ if (ext.endsWith('.go')) {
8
+ return 'go';
9
+ }
10
+ return super.detectLanguage();
11
+ }
12
+
13
+ parseAST(): unknown {
14
+ return {
15
+ content: this.fileContent,
16
+ language: 'go',
17
+ filePath: this.filePath
18
+ };
19
+ }
20
+
21
+ extractFunctions(): unknown[] {
22
+ const functionMatches = [];
23
+ const fnRegex = /func\s+(\(\w+\s+\*?\w+\)\s+)?(\w+)\s*\([^)]*\)\s*({)?/g;
24
+ let match;
25
+
26
+ while ((match = fnRegex.exec(this.fileContent)) !== null) {
27
+ functionMatches.push({
28
+ name: match[2],
29
+ type: match[1] ? 'method' : 'function',
30
+ receiver: match[1] ? match[1].trim() : null,
31
+ line: this.getLineNumber(match.index),
32
+ code: this.extractCodeBlock(match.index)
33
+ });
34
+ }
35
+
36
+ return functionMatches;
37
+ }
38
+
39
+ extractClasses(): unknown[] {
40
+ const structMatches = [];
41
+ const structRegex = /type\s+(\w+)\s+struct\s*{/g;
42
+ let match;
43
+
44
+ while ((match = structRegex.exec(this.fileContent)) !== null) {
45
+ structMatches.push({
46
+ name: match[1],
47
+ type: 'struct',
48
+ line: this.getLineNumber(match.index),
49
+ code: this.extractCodeBlock(match.index)
50
+ });
51
+ }
52
+
53
+ return structMatches;
54
+ }
55
+ }
@@ -0,0 +1,56 @@
1
+ import { BaseAdapter } from './base';
2
+ import { Adapter } from '../types';
3
+
4
+ export class JavaAdapter extends BaseAdapter implements Adapter {
5
+ detectLanguage(): string {
6
+ const ext = this.filePath.toLowerCase();
7
+ if (ext.endsWith('.java')) {
8
+ return 'java';
9
+ }
10
+ return super.detectLanguage();
11
+ }
12
+
13
+ parseAST(): unknown {
14
+ return {
15
+ content: this.fileContent,
16
+ language: 'java',
17
+ filePath: this.filePath
18
+ };
19
+ }
20
+
21
+ extractFunctions(): unknown[] {
22
+ const methodMatches = [];
23
+ const methodRegex = /(public|private|protected|static|final|synchronized|native)\s+[\w<>[\]]+\s+(\w+)\s*\([^)]*\)\s*(throws\s+[\w,\s]+)?\s*{/g;
24
+ let match;
25
+
26
+ while ((match = methodRegex.exec(this.fileContent)) !== null) {
27
+ methodMatches.push({
28
+ name: match[2],
29
+ type: 'method',
30
+ modifiers: match[1].split(' ').filter(m => m.trim()),
31
+ line: this.getLineNumber(match.index),
32
+ code: this.extractCodeBlock(match.index)
33
+ });
34
+ }
35
+
36
+ return methodMatches;
37
+ }
38
+
39
+ extractClasses(): unknown[] {
40
+ const classMatches = [];
41
+ const classRegex = /(public|private|protected)?\s*(abstract|final|static)?\s*class\s+(\w+)\s*(extends\s+\w+)?\s*(implements\s+[\w,\s]+)?\s*{/g;
42
+ let match;
43
+
44
+ while ((match = classRegex.exec(this.fileContent)) !== null) {
45
+ classMatches.push({
46
+ name: match[3],
47
+ type: 'class',
48
+ modifiers: [match[1], match[2]].filter(m => m && m.trim()),
49
+ line: this.getLineNumber(match.index),
50
+ code: this.extractCodeBlock(match.index)
51
+ });
52
+ }
53
+
54
+ return classMatches;
55
+ }
56
+ }
@@ -0,0 +1,54 @@
1
+ import { BaseAdapter } from './base';
2
+ import { Adapter } from '../types';
3
+
4
+ export class KotlinAdapter extends BaseAdapter implements Adapter {
5
+ detectLanguage(): string {
6
+ const ext = this.filePath.toLowerCase();
7
+ if (ext.endsWith('.kt') || ext.endsWith('.kts')) {
8
+ return 'kotlin';
9
+ }
10
+ return super.detectLanguage();
11
+ }
12
+
13
+ parseAST(): unknown {
14
+ return {
15
+ content: this.fileContent,
16
+ language: 'kotlin',
17
+ filePath: this.filePath
18
+ };
19
+ }
20
+
21
+ extractFunctions(): unknown[] {
22
+ const functionMatches = [];
23
+ const fnRegex = /(suspend\s+)?fun\s+(\w+)\s*\([^)]*\)\s*(:\s*[\w<>?]+)?\s*{/g;
24
+ let match;
25
+
26
+ while ((match = fnRegex.exec(this.fileContent)) !== null) {
27
+ functionMatches.push({
28
+ name: match[2],
29
+ type: match[1] ? 'suspend_function' : 'function',
30
+ line: this.getLineNumber(match.index),
31
+ code: this.extractCodeBlock(match.index)
32
+ });
33
+ }
34
+
35
+ return functionMatches;
36
+ }
37
+
38
+ extractClasses(): unknown[] {
39
+ const classMatches = [];
40
+ const classRegex = /class\s+(\w+)/g;
41
+ let match;
42
+
43
+ while ((match = classRegex.exec(this.fileContent)) !== null) {
44
+ classMatches.push({
45
+ name: match[1],
46
+ type: 'class',
47
+ line: this.getLineNumber(match.index),
48
+ code: this.extractCodeBlock(match.index)
49
+ });
50
+ }
51
+
52
+ return classMatches;
53
+ }
54
+ }