ctxman 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/.ctxman/custom-profiles.example.json +20 -0
  2. package/.ctxman/llm-profiles.json +131 -0
  3. package/.ctxman/logs/ctxman-2026-07-02.log +156 -0
  4. package/.ctxman/self-knowledge/documents.lance/_transactions/0-b3dd1558-f95b-44b9-a154-18e8c330ae7a.txn +0 -0
  5. package/.ctxman/self-knowledge/documents.lance/_transactions/1-44bff6d4-e552-4010-a769-e09ad822698d.txn +0 -0
  6. package/.ctxman/self-knowledge/documents.lance/_transactions/10-37260794-5947-4ecb-b4c8-d732f58f40f1.txn +0 -0
  7. package/.ctxman/self-knowledge/documents.lance/_transactions/11-0d52a883-5518-463c-9b6d-986c3af89dfd.txn +0 -0
  8. package/.ctxman/self-knowledge/documents.lance/_transactions/12-ae354646-52f2-49c9-90fb-2e6ed8932663.txn +0 -0
  9. package/.ctxman/self-knowledge/documents.lance/_transactions/13-5d7d5e57-27da-498b-b734-091b9d38da13.txn +0 -0
  10. package/.ctxman/self-knowledge/documents.lance/_transactions/14-558ce928-810b-4252-a364-fdd1ee6f8a25.txn +0 -0
  11. package/.ctxman/self-knowledge/documents.lance/_transactions/15-27e3a58f-8b64-43b8-a9f4-e3369446968b.txn +0 -0
  12. package/.ctxman/self-knowledge/documents.lance/_transactions/16-a110c390-e5c8-4464-b976-bc7f5195fa15.txn +0 -0
  13. package/.ctxman/self-knowledge/documents.lance/_transactions/17-97513225-53de-4216-b61a-6337bd0cc4ad.txn +0 -0
  14. package/.ctxman/self-knowledge/documents.lance/_transactions/18-5ba450f0-c527-459c-bf4f-6d79b5e4285f.txn +0 -0
  15. package/.ctxman/self-knowledge/documents.lance/_transactions/19-600d3a63-5225-49e9-b8b7-30e037b564ab.txn +0 -0
  16. package/.ctxman/self-knowledge/documents.lance/_transactions/2-48a61b4e-92cf-4342-8376-914c1b99a9f9.txn +0 -0
  17. package/.ctxman/self-knowledge/documents.lance/_transactions/20-121dd912-5410-410e-84ff-82c7a23604a0.txn +0 -0
  18. package/.ctxman/self-knowledge/documents.lance/_transactions/3-bc6844ab-7ea3-4bb3-9ee1-538ce5664a9c.txn +0 -0
  19. package/.ctxman/self-knowledge/documents.lance/_transactions/4-d5e1754f-dbb5-454e-a9be-2a7da8d7bcf9.txn +0 -0
  20. package/.ctxman/self-knowledge/documents.lance/_transactions/5-4fae93df-0568-4b6f-8acf-8bef4bba6047.txn +0 -0
  21. package/.ctxman/self-knowledge/documents.lance/_transactions/6-4b1b8b87-068e-49a3-ba2b-d8dae628b252.txn +0 -0
  22. package/.ctxman/self-knowledge/documents.lance/_transactions/7-63d040fb-d2fa-4c0f-bed0-53411918a7b0.txn +0 -0
  23. package/.ctxman/self-knowledge/documents.lance/_transactions/8-c5628cf6-264c-420f-aab8-bc96a9083591.txn +0 -0
  24. package/.ctxman/self-knowledge/documents.lance/_transactions/9-c94570aa-5e53-4fcb-971f-cecc1d1d5492.txn +0 -0
  25. package/.ctxman/self-knowledge/documents.lance/_versions/1.manifest +0 -0
  26. package/.ctxman/self-knowledge/documents.lance/_versions/10.manifest +0 -0
  27. package/.ctxman/self-knowledge/documents.lance/_versions/11.manifest +0 -0
  28. package/.ctxman/self-knowledge/documents.lance/_versions/12.manifest +0 -0
  29. package/.ctxman/self-knowledge/documents.lance/_versions/13.manifest +0 -0
  30. package/.ctxman/self-knowledge/documents.lance/_versions/14.manifest +0 -0
  31. package/.ctxman/self-knowledge/documents.lance/_versions/15.manifest +0 -0
  32. package/.ctxman/self-knowledge/documents.lance/_versions/16.manifest +0 -0
  33. package/.ctxman/self-knowledge/documents.lance/_versions/17.manifest +0 -0
  34. package/.ctxman/self-knowledge/documents.lance/_versions/18.manifest +0 -0
  35. package/.ctxman/self-knowledge/documents.lance/_versions/19.manifest +0 -0
  36. package/.ctxman/self-knowledge/documents.lance/_versions/2.manifest +0 -0
  37. package/.ctxman/self-knowledge/documents.lance/_versions/20.manifest +0 -0
  38. package/.ctxman/self-knowledge/documents.lance/_versions/21.manifest +0 -0
  39. package/.ctxman/self-knowledge/documents.lance/_versions/3.manifest +0 -0
  40. package/.ctxman/self-knowledge/documents.lance/_versions/4.manifest +0 -0
  41. package/.ctxman/self-knowledge/documents.lance/_versions/5.manifest +0 -0
  42. package/.ctxman/self-knowledge/documents.lance/_versions/6.manifest +0 -0
  43. package/.ctxman/self-knowledge/documents.lance/_versions/7.manifest +0 -0
  44. package/.ctxman/self-knowledge/documents.lance/_versions/8.manifest +0 -0
  45. package/.ctxman/self-knowledge/documents.lance/_versions/9.manifest +0 -0
  46. package/.ctxman/self-knowledge/documents.lance/data/000010010011011101000010de8621405d9d5cb06540dbf02c.lance +0 -0
  47. package/.ctxman/self-knowledge/documents.lance/data/0000101001011100011000003fb62a4aa8978974075c144f1c.lance +0 -0
  48. package/.ctxman/self-knowledge/documents.lance/data/000011010000100111001011c6cc824d628f3bb1f4e04cd5d0.lance +0 -0
  49. package/.ctxman/self-knowledge/documents.lance/data/001000001000011001011100d8f74349ada090b332cd1df669.lance +0 -0
  50. package/.ctxman/self-knowledge/documents.lance/data/01000001111010001000010045ab44467bb1e7e4d8ae06bd58.lance +0 -0
  51. package/.ctxman/self-knowledge/documents.lance/data/01000101101110111110011131ef904241a89e1ffb6ddaf8e3.lance +0 -0
  52. package/.ctxman/self-knowledge/documents.lance/data/010010110000010000011010fbfcc145c6a8a827b28057a07e.lance +0 -0
  53. package/.ctxman/self-knowledge/documents.lance/data/1000011000101010001110003fb4f045c3835982efa1405324.lance +0 -0
  54. package/.ctxman/self-knowledge/documents.lance/data/100111011101110111101011f4396b410fa06af3b028d204e6.lance +0 -0
  55. package/.ctxman/self-knowledge/documents.lance/data/100111100111101000001100596b174e00995d6cc2969cc8dc.lance +0 -0
  56. package/.ctxman/self-knowledge/documents.lance/data/1010001100011000110010102ea16b484d887c7c9725feffd6.lance +0 -0
  57. package/.ctxman/self-knowledge/documents.lance/data/101101100010101111110111c5230944d9b3af7301b6392dda.lance +0 -0
  58. package/.ctxman/self-knowledge/documents.lance/data/1011011100100111111110105892bf41b5a530fedd7cf516f1.lance +0 -0
  59. package/.ctxman/self-knowledge/documents.lance/data/10111110000010001011110164e8774742bade87b483c10f36.lance +0 -0
  60. package/.ctxman/self-knowledge/documents.lance/data/1100000100010110001110103ffaca40a2a42c85067ebaf9ae.lance +0 -0
  61. package/.ctxman/self-knowledge/documents.lance/data/110000010001110110101110664bde4c76a78dfc14b05e83b8.lance +0 -0
  62. package/.ctxman/self-knowledge/documents.lance/data/11001100111000010100110050645c4281b1f35b2022234f7f.lance +0 -0
  63. package/.ctxman/self-knowledge/documents.lance/data/1101111011001100110111017214924a368f5719eab2246619.lance +0 -0
  64. package/.ctxman/self-knowledge/documents.lance/data/1110000111001010001000002150c24dcab653d39d07032e63.lance +0 -0
  65. package/.ctxman/self-knowledge/documents.lance/data/1110100000000100000011014d20534967a18b5c87721659ff.lance +0 -0
  66. package/.ctxman/self-knowledge/documents.lance/data/11110101111010000101011135a0114ef2b35dc6f1297a3381.lance +0 -0
  67. package/.ctxman/wizard-profiles/code-review/.contextignore +41 -0
  68. package/.ctxman/wizard-profiles/code-review/.contextinclude +30 -0
  69. package/.ctxman/wizard-profiles/code-review/.methodignore +26 -0
  70. package/.ctxman/wizard-profiles/code-review/.methodinclude +47 -0
  71. package/.ctxman/wizard-profiles/code-review/profile.json +26 -0
  72. package/.ctxman/wizard-profiles/documentation/.contextignore +21 -0
  73. package/.ctxman/wizard-profiles/documentation/.contextinclude +24 -0
  74. package/.ctxman/wizard-profiles/documentation/.methodignore +19 -0
  75. package/.ctxman/wizard-profiles/documentation/.methodinclude +44 -0
  76. package/.ctxman/wizard-profiles/documentation/profile.json +27 -0
  77. package/.ctxman/wizard-profiles/full/.contextignore +23 -0
  78. package/.ctxman/wizard-profiles/full/.contextinclude +38 -0
  79. package/.ctxman/wizard-profiles/full/.methodignore +5 -0
  80. package/.ctxman/wizard-profiles/full/.methodinclude +5 -0
  81. package/.ctxman/wizard-profiles/full/profile.json +28 -0
  82. package/.ctxman/wizard-profiles/llm-explain/.contextignore +25 -0
  83. package/.ctxman/wizard-profiles/llm-explain/.contextinclude +33 -0
  84. package/.ctxman/wizard-profiles/llm-explain/.methodignore +19 -0
  85. package/.ctxman/wizard-profiles/llm-explain/.methodinclude +48 -0
  86. package/.ctxman/wizard-profiles/llm-explain/profile.json +27 -0
  87. package/.ctxman/wizard-profiles/minimal/.contextignore +27 -0
  88. package/.ctxman/wizard-profiles/minimal/.contextinclude +14 -0
  89. package/.ctxman/wizard-profiles/minimal/.methodignore +22 -0
  90. package/.ctxman/wizard-profiles/minimal/.methodinclude +18 -0
  91. package/.ctxman/wizard-profiles/minimal/profile.json +26 -0
  92. package/.ctxman/wizard-profiles/security-audit/.contextignore +36 -0
  93. package/.ctxman/wizard-profiles/security-audit/.contextinclude +37 -0
  94. package/.ctxman/wizard-profiles/security-audit/.methodignore +29 -0
  95. package/.ctxman/wizard-profiles/security-audit/.methodinclude +60 -0
  96. package/.ctxman/wizard-profiles/security-audit/profile.json +34 -0
  97. package/README.md +1167 -0
  98. package/bin/cli.js +650 -0
  99. package/bin/cm-ask.js +95 -0
  100. package/bin/cm-gitingest.js +134 -0
  101. package/bin/cm-update.js +175 -0
  102. package/bin/mcp-server.js +31 -0
  103. package/ctxman.js +236 -0
  104. package/examples/README.md +298 -0
  105. package/examples/custom-llm-profiles.example.json +19 -0
  106. package/examples/wizard-profiles/code-review/.contextignore +41 -0
  107. package/examples/wizard-profiles/code-review/.contextinclude +30 -0
  108. package/examples/wizard-profiles/code-review/.methodignore +26 -0
  109. package/examples/wizard-profiles/code-review/.methodinclude +47 -0
  110. package/examples/wizard-profiles/code-review/profile.json +26 -0
  111. package/examples/wizard-profiles/documentation/.contextignore +21 -0
  112. package/examples/wizard-profiles/documentation/.contextinclude +24 -0
  113. package/examples/wizard-profiles/documentation/.methodignore +19 -0
  114. package/examples/wizard-profiles/documentation/.methodinclude +44 -0
  115. package/examples/wizard-profiles/documentation/profile.json +27 -0
  116. package/examples/wizard-profiles/full/.contextignore +23 -0
  117. package/examples/wizard-profiles/full/.contextinclude +38 -0
  118. package/examples/wizard-profiles/full/.methodignore +5 -0
  119. package/examples/wizard-profiles/full/.methodinclude +5 -0
  120. package/examples/wizard-profiles/full/profile.json +28 -0
  121. package/examples/wizard-profiles/llm-explain/.contextignore +25 -0
  122. package/examples/wizard-profiles/llm-explain/.contextinclude +33 -0
  123. package/examples/wizard-profiles/llm-explain/.methodignore +19 -0
  124. package/examples/wizard-profiles/llm-explain/.methodinclude +48 -0
  125. package/examples/wizard-profiles/llm-explain/profile.json +27 -0
  126. package/examples/wizard-profiles/minimal/.contextignore +27 -0
  127. package/examples/wizard-profiles/minimal/.contextinclude +14 -0
  128. package/examples/wizard-profiles/minimal/.methodignore +22 -0
  129. package/examples/wizard-profiles/minimal/.methodinclude +18 -0
  130. package/examples/wizard-profiles/minimal/profile.json +26 -0
  131. package/examples/wizard-profiles/security-audit/.contextignore +36 -0
  132. package/examples/wizard-profiles/security-audit/.contextinclude +37 -0
  133. package/examples/wizard-profiles/security-audit/.methodignore +29 -0
  134. package/examples/wizard-profiles/security-audit/.methodinclude +60 -0
  135. package/examples/wizard-profiles/security-audit/profile.json +34 -0
  136. package/index.js +68 -0
  137. package/lib/agents/pr-failure-agent.js +201 -0
  138. package/lib/analyzers/go-method-analyzer.js +126 -0
  139. package/lib/analyzers/method-analyzer.js +457 -0
  140. package/lib/analyzers/token-calculator.js +577 -0
  141. package/lib/api/mcp/prompts.js +319 -0
  142. package/lib/api/mcp/resources.js +269 -0
  143. package/lib/api/mcp/server.js +339 -0
  144. package/lib/api/mcp/transports/HttpSseTransport.js +63 -0
  145. package/lib/api/rest/server.js +405 -0
  146. package/lib/cache/CacheManager.js +388 -0
  147. package/lib/core/Analyzer.js +180 -0
  148. package/lib/core/ContextBuilder.js +325 -0
  149. package/lib/core/Reporter.js +270 -0
  150. package/lib/core/Scanner.js +129 -0
  151. package/lib/formatters/format-registry.js +419 -0
  152. package/lib/formatters/gitingest-formatter.js +746 -0
  153. package/lib/formatters/toon-formatter-v1.3.js +731 -0
  154. package/lib/formatters/toon-formatter.js +291 -0
  155. package/lib/integrations/git/BlameTracker.js +142 -0
  156. package/lib/integrations/git/DiffAnalyzer.js +260 -0
  157. package/lib/integrations/git/GitClient.js +336 -0
  158. package/lib/parsers/gitignore-parser.js +127 -0
  159. package/lib/parsers/method-filter-parser.js +50 -0
  160. package/lib/plugins/ExporterPlugin.js +102 -0
  161. package/lib/plugins/LanguagePlugin.js +100 -0
  162. package/lib/plugins/PluginManager.js +302 -0
  163. package/lib/rag/DataSourcePlugin.js +31 -0
  164. package/lib/rag/EmbeddingProvider.js +75 -0
  165. package/lib/rag/Indexer.js +83 -0
  166. package/lib/rag/VectorStoreFactory.js +24 -0
  167. package/lib/rag/sources/FileDataSource.js +70 -0
  168. package/lib/rag/stores/BaseVectorStore.js +43 -0
  169. package/lib/rag/stores/ChromaDBStore.js +85 -0
  170. package/lib/rag/stores/LanceDBStore.js +109 -0
  171. package/lib/rag/stores/PineconeStore.js +74 -0
  172. package/lib/ui/dashboard.js +109 -0
  173. package/lib/ui/index.js +15 -0
  174. package/lib/ui/progress-bar.js +110 -0
  175. package/lib/ui/select-input.js +51 -0
  176. package/lib/ui/wizard.js +359 -0
  177. package/lib/utils/clipboard-utils.js +66 -0
  178. package/lib/utils/config-utils.js +94 -0
  179. package/lib/utils/error-handler.js +145 -0
  180. package/lib/utils/file-utils.js +89 -0
  181. package/lib/utils/format-converter.js +325 -0
  182. package/lib/utils/git-utils.js +337 -0
  183. package/lib/utils/llm-detector.js +409 -0
  184. package/lib/utils/logger.js +278 -0
  185. package/lib/utils/token-utils.js +200 -0
  186. package/lib/utils/tokenizer-adapter.js +454 -0
  187. package/lib/utils/updater.js +565 -0
  188. package/lib/watch/FileWatcher.js +208 -0
  189. package/lib/watch/IncrementalAnalyzer.js +206 -0
  190. package/package.json +118 -0
@@ -0,0 +1,457 @@
1
+ /**
2
+ * Method-Level Code Analyzer
3
+ * Extracts methods from JavaScript/TypeScript/Rust/C#/Go/Java/Python/PHP/Ruby/Kotlin/Swift/C/C++/Scala files
4
+ */
5
+
6
+ import path from 'path';
7
+ import GoMethodAnalyzer from './go-method-analyzer.js';
8
+
9
+ class MethodAnalyzer {
10
+ constructor() {
11
+ this.goAnalyzer = new GoMethodAnalyzer();
12
+ }
13
+
14
+ extractMethods(content, filePath) {
15
+ const ext = path.extname(filePath).toLowerCase();
16
+
17
+ // Determine which analyzer to use based on file type
18
+ if (ext === '.rs') {
19
+ return this.extractRustMethods(content, filePath);
20
+ } else if (ext === '.go') {
21
+ return this.goAnalyzer.extractMethods(content, filePath);
22
+ } else if (ext === '.java') {
23
+ return this.extractJavaMethods(content, filePath);
24
+ } else if (ext === '.cs') {
25
+ return this.extractCSharpMethods(content, filePath);
26
+ } else if (ext === '.py') {
27
+ return this.extractPythonMethods(content, filePath);
28
+ } else if (ext === '.php') {
29
+ return this.extractPHPMethods(content, filePath);
30
+ } else if (ext === '.rb') {
31
+ return this.extractRubyMethods(content, filePath);
32
+ } else if (ext === '.kt' || ext === '.kts') {
33
+ return this.extractKotlinMethods(content, filePath);
34
+ } else if (ext === '.swift') {
35
+ return this.extractSwiftMethods(content, filePath);
36
+ } else if (ext === '.c' || ext === '.cpp' || ext === '.cc' || ext === '.h' || ext === '.hpp') {
37
+ return this.extractCPlusPlusMethods(content, filePath);
38
+ } else if (ext === '.scala') {
39
+ return this.extractScalaMethods(content, filePath);
40
+ } else {
41
+ return this.extractJavaScriptMethods(content, filePath);
42
+ }
43
+ }
44
+
45
+ extractJavaScriptMethods(content, filePath) {
46
+ // Support \w, $, _ for method names
47
+ const namePattern = '[\\w$_]+';
48
+
49
+ const patterns = [
50
+ // Order matters: More specific patterns first to avoid overlaps
51
+ { regex: new RegExp(`(?:export\\s+)?(?:async\\s+)?function\\s+(${namePattern})\\s*\\(`, 'g'), type: 'function' },
52
+ { regex: new RegExp(`(${namePattern})\\s*:\\s*(?:async\\s+)?function\\s*\\(`, 'g'), type: 'method' },
53
+ { regex: new RegExp(`(?:const|let|var)\\s+(${namePattern})\\s*=\\s*(?:async\\s+)?\\([^)]*\\)\\s*=>`, 'g'), type: 'arrow' },
54
+ { regex: new RegExp(`(get|set)\\s+(${namePattern})\\s*\\(`, 'g'), type: 'accessor' },
55
+ // Shorthand pattern (class methods) - must be last to avoid conflicts
56
+ { regex: new RegExp(`(?:async\\s+)?(${namePattern})\\s*\\([^)]*\\)\\s*\\{`, 'g'), type: 'shorthand' },
57
+ ];
58
+
59
+ return this.processPatterns(content, filePath, patterns);
60
+ }
61
+
62
+ extractJavaMethods(content, filePath) {
63
+ const namePattern = '[\\w]+';
64
+
65
+ const patterns = [
66
+ // Public/private/protected methods with return type
67
+ {
68
+ regex: new RegExp(`(?:public|private|protected|static|final|synchronized|native|abstract|\\s)+(?:<[^>]+>\\s+)?(?:[\\w<>\\[\\],\\s]+)\\s+(${namePattern})\\s*\\(`, 'g'),
69
+ type: 'method'
70
+ },
71
+ // Constructor (same name as class)
72
+ {
73
+ regex: new RegExp(`(?:public|private|protected)?\\s+(${namePattern})\\s*\\([^)]*\\)\\s*(?:throws\\s+[\\w,\\s]+)?\\s*\\{`, 'g'),
74
+ type: 'constructor'
75
+ },
76
+ ];
77
+
78
+ return this.processPatterns(content, filePath, patterns, true);
79
+ }
80
+
81
+ extractCSharpMethods(content, filePath) {
82
+ const namePattern = '[\\w]+';
83
+
84
+ const patterns = [
85
+ // C# method patterns with modifiers and return types
86
+ // Matches: public/private/protected/internal static/async returnType MethodName(params) {
87
+ {
88
+ regex: new RegExp(
89
+ `(?:public|private|protected|internal)?\\s*` +
90
+ `(?:static|virtual|override|abstract|async)?\\s*` +
91
+ `(?:partial)?\\s*` +
92
+ `(?:void|bool|int|string|double|float|long|decimal|object|var|Task|${namePattern}(?:<[^>]+>)?(?:\\[\\])?)?\\s+` +
93
+ `(${namePattern})\\s*` +
94
+ `(?:<[^>]+>)?\\s*` + // Generic type parameters
95
+ `\\([^)]*\\)\\s*` +
96
+ `(?:where\\s+[^{]+)?\\s*` + // Generic constraints
97
+ `\\{`,
98
+ 'g'
99
+ ),
100
+ type: 'method'
101
+ },
102
+ // Property getters/setters
103
+ {
104
+ regex: new RegExp(
105
+ `(?:public|private|protected|internal)?\\s*` +
106
+ `(?:static|virtual|override|abstract)?\\s*` +
107
+ `(?:${namePattern}(?:<[^>]+>)?(?:\\[\\])?)?\\s+` +
108
+ `(${namePattern})\\s*` +
109
+ `\\{\\s*(?:get|set)`,
110
+ 'g'
111
+ ),
112
+ type: 'property'
113
+ },
114
+ // Expression-bodied members (C# 6.0+)
115
+ // Matches: public Type MethodName() => expression;
116
+ {
117
+ regex: new RegExp(
118
+ `(?:public|private|protected|internal)?\\s*` +
119
+ `(?:static|virtual|override|abstract)?\\s*` +
120
+ `(?:${namePattern}(?:<[^>]+>)?(?:\\[\\])?)?\\s+` +
121
+ `(${namePattern})\\s*` +
122
+ `(?:<[^>]+>)?\\s*` +
123
+ `\\([^)]*\\)\\s*=>`,
124
+ 'g'
125
+ ),
126
+ type: 'expression-bodied'
127
+ }
128
+ ];
129
+
130
+ return this.processPatterns(content, filePath, patterns, false, true);
131
+ }
132
+
133
+ processPatterns(content, filePath, patterns, isJava = false, isCSharp = false, isPython = false, isRuby = false, isKotlin = false, isSwift = false, isScala = false) {
134
+ const methodsMap = new Map();
135
+ const processedLines = new Map(); // Track processed lines to avoid duplicates
136
+
137
+ patterns.forEach(({ regex, type }) => {
138
+ let match;
139
+ while ((match = regex.exec(content)) !== null) {
140
+ let methodName;
141
+ let accessorType = '';
142
+
143
+ if (type === 'accessor') {
144
+ accessorType = match[1];
145
+ methodName = match[2];
146
+ } else {
147
+ methodName = match[1];
148
+ }
149
+
150
+ const line = this.getLineNumber(content, match.index + match[0].indexOf(methodName));
151
+
152
+ // Use appropriate keyword check based on language
153
+ let keywordCheck = false;
154
+ if (isCSharp) {
155
+ keywordCheck = !this.isCSharpKeyword(methodName);
156
+ } else if (isPython) {
157
+ keywordCheck = !this.isPythonKeyword(methodName);
158
+ } else if (isRuby) {
159
+ keywordCheck = !this.isRubyKeyword(methodName);
160
+ } else if (isKotlin) {
161
+ keywordCheck = !this.isKotlinKeyword(methodName);
162
+ } else if (isSwift) {
163
+ keywordCheck = !this.isSwiftKeyword(methodName);
164
+ } else if (isScala) {
165
+ keywordCheck = !this.isScalaKeyword(methodName);
166
+ } else {
167
+ keywordCheck = !this.isKeyword(methodName, isJava);
168
+ }
169
+
170
+ if (methodName && keywordCheck) {
171
+ const key = type === 'accessor'
172
+ ? `${accessorType}_${methodName}:${line}`
173
+ : `${methodName}:${line}`;
174
+
175
+ // Skip if this line was already processed for this method name
176
+ const lineKey = `${methodName}:${line}`;
177
+ if (processedLines.has(lineKey)) {
178
+ continue;
179
+ }
180
+
181
+ if (!methodsMap.has(key)) {
182
+ methodsMap.set(key, {
183
+ name: type === 'accessor' ? `${accessorType} ${methodName}` : methodName,
184
+ line: line,
185
+ file: path.relative(process.cwd(), filePath)
186
+ });
187
+ processedLines.set(lineKey, true);
188
+ }
189
+ }
190
+ }
191
+ });
192
+
193
+ return Array.from(methodsMap.values());
194
+ }
195
+
196
+ extractPythonMethods(content, filePath) {
197
+ const namePattern = '[a-zA-Z_][a-zA-Z0-9_]*';
198
+
199
+ const patterns = [
200
+ // def function_name or async def function_name
201
+ { regex: new RegExp(`^\\s*(?:async\\s+)?def\\s+(${namePattern})\\s*\\(`, 'gm'), type: 'function' },
202
+ // @staticmethod, @classmethod decorators
203
+ { regex: new RegExp(`@(?:staticmethod|classmethod)\\s+def\\s+(${namePattern})\\s*\\(`, 'gm'), type: 'method' },
204
+ ];
205
+
206
+ return this.processPatterns(content, filePath, patterns, false, false, true);
207
+ }
208
+
209
+ extractPHPMethods(content, filePath) {
210
+ const namePattern = '[a-zA-Z_][a-zA-Z0-9_]*';
211
+
212
+ const patterns = [
213
+ // function function_name
214
+ { regex: new RegExp(`function\\s+(${namePattern})\\s*\\(`, 'g'), type: 'function' },
215
+ // public/private/protected function method_name
216
+ { regex: new RegExp(`(?:public|private|protected)?\\s*(?:static)?\\s*function\\s+(${namePattern})\\s*\\(`, 'g'), type: 'method' },
217
+ ];
218
+
219
+ return this.processPatterns(content, filePath, patterns);
220
+ }
221
+
222
+ extractRubyMethods(content, filePath) {
223
+ const namePattern = '[a-zA-Z_][a-zA-Z0-9_]*[?!]?';
224
+
225
+ const patterns = [
226
+ // def method_name or def self.method_name
227
+ { regex: new RegExp(`^\\s*def\\s+(?:self\\.)?(${namePattern})\\s*(?:\\(|$)`, 'gm'), type: 'method' },
228
+ ];
229
+
230
+ return this.processPatterns(content, filePath, patterns, false, false, false, true);
231
+ }
232
+
233
+ extractKotlinMethods(content, filePath) {
234
+ const namePattern = '[a-zA-Z_][a-zA-Z0-9_]*';
235
+
236
+ const patterns = [
237
+ // fun functionName or fun ClassName.functionName
238
+ { regex: new RegExp(`(?:public|private|protected|internal)?\\s*(?:suspend\\s+)?(?:inline\\s+)?fun\\s+(?:<[^>]+>\\s+)?(?:[\\w.]+\\.)?\\s*(${namePattern})\\s*(?:<[^>]+>)?\\s*\\(`, 'g'), type: 'function' },
239
+ ];
240
+
241
+ return this.processPatterns(content, filePath, patterns, false, false, false, false, true);
242
+ }
243
+
244
+ extractSwiftMethods(content, filePath) {
245
+ const namePattern = '[a-zA-Z_][a-zA-Z0-9_]*';
246
+
247
+ const patterns = [
248
+ // func functionName
249
+ { regex: new RegExp(`(?:public|private|internal|fileprivate)?\\s*(?:static|class)?\\s*func\\s+(${namePattern})\\s*(?:<[^>]+>)?\\s*\\(`, 'g'), type: 'function' },
250
+ // init (constructors)
251
+ { regex: new RegExp(`(?:public|private|internal|fileprivate)?\\s*(?:convenience\\s+)?init\\s*\\(`, 'g'), type: 'init' },
252
+ ];
253
+
254
+ return this.processPatterns(content, filePath, patterns, false, false, false, false, false, true);
255
+ }
256
+
257
+ extractCPlusPlusMethods(content, filePath) {
258
+ const namePattern = '[a-zA-Z_][a-zA-Z0-9_]*';
259
+
260
+ const patterns = [
261
+ // Return type function_name( or ClassName::function_name(
262
+ { regex: new RegExp(`(?:virtual\\s+)?(?:static\\s+)?(?:inline\\s+)?(?:[\\w:]+\\s+)?(?:[\\w:]+::)?(${namePattern})\\s*\\([^)]*\\)\\s*(?:const)?\\s*(?:override)?\\s*(?:final)?\\s*\\{`, 'g'), type: 'function' },
263
+ // Constructor: ClassName::ClassName(
264
+ { regex: new RegExp(`(${namePattern})\\s*\\([^)]*\\)\\s*:\\s*`, 'g'), type: 'constructor' },
265
+ ];
266
+
267
+ return this.processPatterns(content, filePath, patterns);
268
+ }
269
+
270
+ extractScalaMethods(content, filePath) {
271
+ const namePattern = '[a-zA-Z_][a-zA-Z0-9_]*';
272
+
273
+ const patterns = [
274
+ // def methodName
275
+ { regex: new RegExp(`(?:override\\s+)?def\\s+(${namePattern})\\s*(?:\\[|\\(|:)`, 'g'), type: 'method' },
276
+ // val/var with function assignment
277
+ { regex: new RegExp(`(?:val|var)\\s+(${namePattern})\\s*=\\s*\\([^)]*\\)\\s*=>`, 'g'), type: 'function' },
278
+ ];
279
+
280
+ return this.processPatterns(content, filePath, patterns, false, false, false, false, false, false, true);
281
+ }
282
+
283
+ extractRustMethods(content, filePath) {
284
+ // Rust method name pattern (snake_case and alphanumeric)
285
+ const namePattern = '[a-zA-Z_][a-zA-Z0-9_]*';
286
+
287
+ const patterns = [
288
+ // pub fn function_name or fn function_name
289
+ { regex: new RegExp(`(?:pub\\s+)?(?:async\\s+)?(?:const\\s+)?(?:unsafe\\s+)?fn\\s+(${namePattern})\\s*[<(]`, 'g'), type: 'function' },
290
+ // impl methods: fn method_name (inside impl blocks)
291
+ { regex: new RegExp(`^\\s*(?:pub\\s+)?(?:async\\s+)?(?:const\\s+)?(?:unsafe\\s+)?fn\\s+(${namePattern})\\s*[<(]`, 'gm'), type: 'method' },
292
+ ];
293
+
294
+ const methodsMap = new Map();
295
+ const processedLines = new Map();
296
+
297
+ patterns.forEach(({ regex, type }) => {
298
+ let match;
299
+ while ((match = regex.exec(content)) !== null) {
300
+ const methodName = match[1];
301
+ const line = this.getLineNumber(content, match.index + match[0].indexOf(methodName));
302
+
303
+ if (methodName && !this.isRustKeyword(methodName)) {
304
+ const key = `${methodName}:${line}`;
305
+ const lineKey = `${methodName}:${line}`;
306
+
307
+ if (processedLines.has(lineKey)) {
308
+ continue;
309
+ }
310
+
311
+ if (!methodsMap.has(key)) {
312
+ methodsMap.set(key, {
313
+ name: methodName,
314
+ line: line,
315
+ file: path.relative(process.cwd(), filePath)
316
+ });
317
+ processedLines.set(lineKey, true);
318
+ }
319
+ }
320
+ }
321
+ });
322
+
323
+ return Array.from(methodsMap.values());
324
+ }
325
+
326
+ getLineNumber(content, index) {
327
+ return content.substring(0, index).split('\n').length;
328
+ }
329
+
330
+ isKeyword(name, isJava = false) {
331
+ const jsKeywords = new Set([
332
+ 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'default',
333
+ 'try', 'catch', 'finally', 'throw', 'return', 'break', 'continue',
334
+ 'class', 'extends', 'super', 'this', 'new', 'typeof', 'instanceof',
335
+ 'var', 'let', 'const', 'function', 'async', 'await', 'export', 'import'
336
+ ]);
337
+
338
+ const javaKeywords = new Set([
339
+ 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'default',
340
+ 'try', 'catch', 'finally', 'throw', 'return', 'break', 'continue',
341
+ 'class', 'extends', 'super', 'this', 'new', 'instanceof',
342
+ 'abstract', 'assert', 'boolean', 'byte', 'char', 'double', 'enum',
343
+ 'final', 'float', 'implements', 'import', 'int', 'interface', 'long',
344
+ 'native', 'package', 'private', 'protected', 'public', 'short', 'static',
345
+ 'strictfp', 'synchronized', 'throws', 'transient', 'void', 'volatile',
346
+ // Common type names to skip
347
+ 'String', 'Integer', 'Boolean', 'Double', 'Float', 'Long', 'Short',
348
+ 'Byte', 'Character', 'List', 'Map', 'Set', 'ArrayList', 'HashMap',
349
+ 'HashSet', 'Object', 'Exception'
350
+ ]);
351
+
352
+ return isJava ? javaKeywords.has(name) : jsKeywords.has(name);
353
+ }
354
+
355
+ isCSharpKeyword(name) {
356
+ const keywords = new Set([
357
+ 'if', 'else', 'for', 'foreach', 'while', 'do', 'switch', 'case', 'default',
358
+ 'try', 'catch', 'finally', 'throw', 'return', 'break', 'continue',
359
+ 'class', 'interface', 'struct', 'enum', 'this', 'base', 'new', 'typeof',
360
+ 'var', 'using', 'namespace', 'async', 'await', 'lock', 'yield',
361
+ 'public', 'private', 'protected', 'internal', 'static', 'virtual',
362
+ 'override', 'abstract', 'sealed', 'partial', 'readonly', 'const'
363
+ ]);
364
+ return keywords.has(name);
365
+ }
366
+
367
+ isRustKeyword(name) {
368
+ const keywords = new Set([
369
+ 'as', 'break', 'const', 'continue', 'crate', 'else', 'enum', 'extern',
370
+ 'false', 'fn', 'for', 'if', 'impl', 'in', 'let', 'loop', 'match',
371
+ 'mod', 'move', 'mut', 'pub', 'ref', 'return', 'self', 'Self', 'static',
372
+ 'struct', 'super', 'trait', 'true', 'type', 'unsafe', 'use', 'where',
373
+ 'while', 'async', 'await', 'dyn', 'abstract', 'become', 'box', 'do',
374
+ 'final', 'macro', 'override', 'priv', 'typeof', 'unsized', 'virtual', 'yield'
375
+ ]);
376
+ return keywords.has(name);
377
+ }
378
+
379
+ isPythonKeyword(name) {
380
+ const keywords = new Set([
381
+ 'False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await',
382
+ 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except',
383
+ 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
384
+ 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return',
385
+ 'try', 'while', 'with', 'yield', '__init__', '__main__'
386
+ ]);
387
+ return keywords.has(name);
388
+ }
389
+
390
+ isRubyKeyword(name) {
391
+ const keywords = new Set([
392
+ 'alias', 'and', 'begin', 'break', 'case', 'class', 'def', 'defined?',
393
+ 'do', 'else', 'elsif', 'end', 'ensure', 'false', 'for', 'if', 'in',
394
+ 'module', 'next', 'nil', 'not', 'or', 'redo', 'rescue', 'retry',
395
+ 'return', 'self', 'super', 'then', 'true', 'undef', 'unless', 'until',
396
+ 'when', 'while', 'yield', 'initialize'
397
+ ]);
398
+ return keywords.has(name);
399
+ }
400
+
401
+ isKotlinKeyword(name) {
402
+ const keywords = new Set([
403
+ 'as', 'break', 'class', 'continue', 'do', 'else', 'false', 'for',
404
+ 'fun', 'if', 'in', 'interface', 'is', 'null', 'object', 'package',
405
+ 'return', 'super', 'this', 'throw', 'true', 'try', 'typealias', 'typeof',
406
+ 'val', 'var', 'when', 'while', 'by', 'catch', 'constructor', 'delegate',
407
+ 'dynamic', 'field', 'file', 'finally', 'get', 'import', 'init', 'param',
408
+ 'property', 'receiver', 'set', 'setparam', 'where', 'actual', 'abstract',
409
+ 'annotation', 'companion', 'const', 'crossinline', 'data', 'enum',
410
+ 'expect', 'external', 'final', 'infix', 'inline', 'inner', 'internal',
411
+ 'lateinit', 'noinline', 'open', 'operator', 'out', 'override', 'private',
412
+ 'protected', 'public', 'reified', 'sealed', 'suspend', 'tailrec', 'vararg'
413
+ ]);
414
+ return keywords.has(name);
415
+ }
416
+
417
+ isSwiftKeyword(name) {
418
+ const keywords = new Set([
419
+ 'associatedtype', 'class', 'deinit', 'enum', 'extension', 'fileprivate',
420
+ 'func', 'import', 'init', 'inout', 'internal', 'let', 'open', 'operator',
421
+ 'private', 'precedencegroup', 'protocol', 'public', 'rethrows', 'static',
422
+ 'struct', 'subscript', 'typealias', 'var', 'break', 'case', 'catch',
423
+ 'continue', 'default', 'defer', 'do', 'else', 'fallthrough', 'for',
424
+ 'guard', 'if', 'in', 'repeat', 'return', 'throw', 'switch', 'where',
425
+ 'while', 'as', 'false', 'is', 'nil', 'self', 'Self', 'super', 'throws',
426
+ 'true', 'try', 'await', 'async'
427
+ ]);
428
+ return keywords.has(name);
429
+ }
430
+
431
+ isScalaKeyword(name) {
432
+ const keywords = new Set([
433
+ 'abstract', 'case', 'catch', 'class', 'def', 'do', 'else', 'extends',
434
+ 'false', 'final', 'finally', 'for', 'forSome', 'if', 'implicit',
435
+ 'import', 'lazy', 'macro', 'match', 'new', 'null', 'object', 'override',
436
+ 'package', 'private', 'protected', 'return', 'sealed', 'super', 'this',
437
+ 'throw', 'trait', 'try', 'true', 'type', 'val', 'var', 'while', 'with',
438
+ 'yield', 'apply', 'unapply'
439
+ ]);
440
+ return keywords.has(name);
441
+ }
442
+
443
+ extractMethodContent(content, methodName) {
444
+ const patterns = [
445
+ new RegExp(`(function\\s+${methodName}\\s*\\([^)]*\\)\\s*\\{[^}]*(?:\\{[^}]*\\}[^}]*)*\\})`, 'g'),
446
+ new RegExp(`(${methodName}\\s*:\\s*function\\s*\\([^)]*\\)\\s*\\{[^}]*(?:\\{[^}]*\\}[^}]*)*\\})`, 'g')
447
+ ];
448
+
449
+ for (const pattern of patterns) {
450
+ const match = pattern.exec(content);
451
+ if (match) return match[1];
452
+ }
453
+ return null;
454
+ }
455
+ }
456
+
457
+ export default MethodAnalyzer;