@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.3
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/README.md +44 -54
- package/bin/cli.js +1 -115
- package/bin/loxia-terminal-v2.js +3 -0
- package/bin/loxia-terminal.js +3 -0
- package/bin/start-with-terminal.js +3 -0
- package/package.json +14 -15
- package/scripts/install-scanners.js +1 -235
- package/src/analyzers/CSSAnalyzer.js +1 -297
- package/src/analyzers/ConfigValidator.js +1 -690
- package/src/analyzers/ESLintAnalyzer.js +1 -320
- package/src/analyzers/JavaScriptAnalyzer.js +1 -261
- package/src/analyzers/PrettierFormatter.js +1 -247
- package/src/analyzers/PythonAnalyzer.js +1 -266
- package/src/analyzers/SecurityAnalyzer.js +1 -729
- package/src/analyzers/TypeScriptAnalyzer.js +1 -247
- package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
- package/src/analyzers/codeCloneDetector/detector.js +1 -203
- package/src/analyzers/codeCloneDetector/index.js +1 -160
- package/src/analyzers/codeCloneDetector/parser.js +1 -199
- package/src/analyzers/codeCloneDetector/reporter.js +1 -148
- package/src/analyzers/codeCloneDetector/scanner.js +1 -59
- package/src/core/agentPool.js +1 -1474
- package/src/core/agentScheduler.js +1 -2147
- package/src/core/contextManager.js +1 -709
- package/src/core/messageProcessor.js +1 -732
- package/src/core/orchestrator.js +1 -548
- package/src/core/stateManager.js +1 -877
- package/src/index.js +1 -631
- package/src/interfaces/cli.js +1 -549
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
- package/src/interfaces/terminal/api/apiClient.js +1 -0
- package/src/interfaces/terminal/api/messageRouter.js +1 -0
- package/src/interfaces/terminal/api/session.js +1 -0
- package/src/interfaces/terminal/api/websocket.js +1 -0
- package/src/interfaces/terminal/components/AgentCreator.js +1 -0
- package/src/interfaces/terminal/components/AgentEditor.js +1 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
- package/src/interfaces/terminal/components/Header.js +1 -0
- package/src/interfaces/terminal/components/HelpPanel.js +1 -0
- package/src/interfaces/terminal/components/InputBox.js +1 -0
- package/src/interfaces/terminal/components/Layout.js +1 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
- package/src/interfaces/terminal/components/MessageList.js +1 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
- package/src/interfaces/terminal/components/SearchPanel.js +1 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
- package/src/interfaces/terminal/components/StatusBar.js +1 -0
- package/src/interfaces/terminal/components/TextInput.js +1 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
- package/src/interfaces/terminal/config/constants.js +1 -0
- package/src/interfaces/terminal/index.js +1 -0
- package/src/interfaces/terminal/state/useAgentControl.js +1 -0
- package/src/interfaces/terminal/state/useAgents.js +1 -0
- package/src/interfaces/terminal/state/useConnection.js +1 -0
- package/src/interfaces/terminal/state/useMessages.js +1 -0
- package/src/interfaces/terminal/state/useTools.js +1 -0
- package/src/interfaces/terminal/utils/debugLogger.js +1 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
- package/src/interfaces/terminal/utils/theme.js +1 -0
- package/src/interfaces/webServer.js +1 -2162
- package/src/modules/fileExplorer/controller.js +1 -280
- package/src/modules/fileExplorer/index.js +1 -37
- package/src/modules/fileExplorer/middleware.js +1 -92
- package/src/modules/fileExplorer/routes.js +1 -125
- package/src/modules/fileExplorer/types.js +1 -44
- package/src/services/aiService.js +1 -1232
- package/src/services/apiKeyManager.js +1 -164
- package/src/services/benchmarkService.js +1 -366
- package/src/services/budgetService.js +1 -539
- package/src/services/contextInjectionService.js +1 -247
- package/src/services/conversationCompactionService.js +1 -637
- package/src/services/errorHandler.js +1 -810
- package/src/services/fileAttachmentService.js +1 -544
- package/src/services/modelRouterService.js +1 -366
- package/src/services/modelsService.js +1 -322
- package/src/services/qualityInspector.js +1 -796
- package/src/services/tokenCountingService.js +1 -536
- package/src/tools/agentCommunicationTool.js +1 -1344
- package/src/tools/agentDelayTool.js +1 -485
- package/src/tools/asyncToolManager.js +1 -604
- package/src/tools/baseTool.js +1 -800
- package/src/tools/browserTool.js +1 -920
- package/src/tools/cloneDetectionTool.js +1 -621
- package/src/tools/dependencyResolverTool.js +1 -1215
- package/src/tools/fileContentReplaceTool.js +1 -875
- package/src/tools/fileSystemTool.js +1 -1107
- package/src/tools/fileTreeTool.js +1 -853
- package/src/tools/imageTool.js +1 -901
- package/src/tools/importAnalyzerTool.js +1 -1060
- package/src/tools/jobDoneTool.js +1 -248
- package/src/tools/seekTool.js +1 -956
- package/src/tools/staticAnalysisTool.js +1 -1778
- package/src/tools/taskManagerTool.js +1 -2873
- package/src/tools/terminalTool.js +1 -2304
- package/src/tools/webTool.js +1 -1430
- package/src/types/agent.js +1 -519
- package/src/types/contextReference.js +1 -972
- package/src/types/conversation.js +1 -730
- package/src/types/toolCommand.js +1 -747
- package/src/utilities/attachmentValidator.js +1 -292
- package/src/utilities/configManager.js +1 -582
- package/src/utilities/constants.js +1 -722
- package/src/utilities/directoryAccessManager.js +1 -535
- package/src/utilities/fileProcessor.js +1 -307
- package/src/utilities/logger.js +1 -436
- package/src/utilities/tagParser.js +1 -1246
- package/src/utilities/toolConstants.js +1 -317
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
- package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
|
@@ -1,247 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* TypeScriptAnalyzer - Analyze TypeScript files for errors using TypeScript Compiler API
|
|
3
|
-
*
|
|
4
|
-
* Purpose:
|
|
5
|
-
* - Analyze TypeScript files for syntax, type, and semantic errors
|
|
6
|
-
* - Use TypeScript Compiler API with full type checking
|
|
7
|
-
* - Provide detailed error information with line numbers
|
|
8
|
-
* - Support TSX syntax
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import ts from 'typescript';
|
|
12
|
-
import path from 'path';
|
|
13
|
-
import { STATIC_ANALYSIS } from '../utilities/constants.js';
|
|
14
|
-
|
|
15
|
-
class TypeScriptAnalyzer {
|
|
16
|
-
constructor(logger = null) {
|
|
17
|
-
this.logger = logger;
|
|
18
|
-
this.compilerOptions = {
|
|
19
|
-
noEmit: true,
|
|
20
|
-
jsx: ts.JsxEmit.React,
|
|
21
|
-
target: ts.ScriptTarget.Latest,
|
|
22
|
-
module: ts.ModuleKind.ESNext,
|
|
23
|
-
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
|
24
|
-
esModuleInterop: true,
|
|
25
|
-
skipLibCheck: true,
|
|
26
|
-
strict: true, // Enable strict type checking for TypeScript
|
|
27
|
-
noImplicitAny: true,
|
|
28
|
-
strictNullChecks: true,
|
|
29
|
-
strictFunctionTypes: true,
|
|
30
|
-
allowJs: false // TypeScript only
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Analyze TypeScript file for errors
|
|
36
|
-
* @param {string} filePath - Path to file
|
|
37
|
-
* @param {string} content - File content
|
|
38
|
-
* @param {Object} options - Analysis options
|
|
39
|
-
* @returns {Promise<Array>} Array of diagnostic errors
|
|
40
|
-
*/
|
|
41
|
-
async analyze(filePath, content, options = {}) {
|
|
42
|
-
try {
|
|
43
|
-
const diagnostics = [];
|
|
44
|
-
|
|
45
|
-
// Create in-memory source file
|
|
46
|
-
const sourceFile = ts.createSourceFile(
|
|
47
|
-
filePath,
|
|
48
|
-
content,
|
|
49
|
-
ts.ScriptTarget.Latest,
|
|
50
|
-
true // setParentNodes
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
// Get syntactic diagnostics (syntax errors)
|
|
54
|
-
const syntacticDiagnostics = this.getSyntacticDiagnostics(sourceFile);
|
|
55
|
-
diagnostics.push(...syntacticDiagnostics);
|
|
56
|
-
|
|
57
|
-
// Get semantic diagnostics (type errors, undefined variables, etc.)
|
|
58
|
-
const semanticDiagnostics = await this.getSemanticDiagnostics(filePath, content);
|
|
59
|
-
diagnostics.push(...semanticDiagnostics);
|
|
60
|
-
|
|
61
|
-
this.logger?.debug('TypeScript analysis completed', {
|
|
62
|
-
file: filePath,
|
|
63
|
-
totalDiagnostics: diagnostics.length,
|
|
64
|
-
errors: diagnostics.filter(d => d.severity === STATIC_ANALYSIS.SEVERITY.ERROR).length,
|
|
65
|
-
warnings: diagnostics.filter(d => d.severity === STATIC_ANALYSIS.SEVERITY.WARNING).length
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
return diagnostics;
|
|
69
|
-
|
|
70
|
-
} catch (error) {
|
|
71
|
-
this.logger?.error('TypeScript analysis failed', {
|
|
72
|
-
file: filePath,
|
|
73
|
-
error: error.message
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
return [{
|
|
77
|
-
file: filePath,
|
|
78
|
-
line: 0,
|
|
79
|
-
column: 0,
|
|
80
|
-
severity: STATIC_ANALYSIS.SEVERITY.ERROR,
|
|
81
|
-
rule: 'analyzer-error',
|
|
82
|
-
message: `Analysis failed: ${error.message}`,
|
|
83
|
-
category: STATIC_ANALYSIS.CATEGORY.SYNTAX
|
|
84
|
-
}];
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Get syntactic diagnostics (syntax errors)
|
|
90
|
-
* @private
|
|
91
|
-
*/
|
|
92
|
-
getSyntacticDiagnostics(sourceFile) {
|
|
93
|
-
const diagnostics = [];
|
|
94
|
-
|
|
95
|
-
// Check for parsing errors
|
|
96
|
-
if (sourceFile.parseDiagnostics && sourceFile.parseDiagnostics.length > 0) {
|
|
97
|
-
for (const diagnostic of sourceFile.parseDiagnostics) {
|
|
98
|
-
diagnostics.push(this.formatDiagnostic(diagnostic, sourceFile));
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return diagnostics;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Get semantic diagnostics (type errors, undefined variables)
|
|
107
|
-
* @private
|
|
108
|
-
*/
|
|
109
|
-
async getSemanticDiagnostics(filePath, content) {
|
|
110
|
-
const diagnostics = [];
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
// Create a minimal program for semantic analysis
|
|
114
|
-
const sourceFile = ts.createSourceFile(
|
|
115
|
-
filePath,
|
|
116
|
-
content,
|
|
117
|
-
ts.ScriptTarget.Latest,
|
|
118
|
-
true
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
// Create a compiler host that provides files from memory
|
|
122
|
-
const host = {
|
|
123
|
-
getSourceFile: (fileName) => {
|
|
124
|
-
if (fileName === filePath) {
|
|
125
|
-
return sourceFile;
|
|
126
|
-
}
|
|
127
|
-
// Return undefined for library files - they won't be available
|
|
128
|
-
return undefined;
|
|
129
|
-
},
|
|
130
|
-
getDefaultLibFileName: () => 'lib.d.ts',
|
|
131
|
-
writeFile: () => {},
|
|
132
|
-
getCurrentDirectory: () => path.dirname(filePath),
|
|
133
|
-
getDirectories: () => [],
|
|
134
|
-
fileExists: (fileName) => fileName === filePath,
|
|
135
|
-
readFile: (fileName) => {
|
|
136
|
-
if (fileName === filePath) {
|
|
137
|
-
return content;
|
|
138
|
-
}
|
|
139
|
-
return undefined;
|
|
140
|
-
},
|
|
141
|
-
getCanonicalFileName: (fileName) => fileName,
|
|
142
|
-
useCaseSensitiveFileNames: () => true,
|
|
143
|
-
getNewLine: () => '\n'
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
// Create program
|
|
147
|
-
const program = ts.createProgram({
|
|
148
|
-
rootNames: [filePath],
|
|
149
|
-
options: this.compilerOptions,
|
|
150
|
-
host
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// Get all diagnostics
|
|
154
|
-
const syntactic = program.getSyntacticDiagnostics(sourceFile);
|
|
155
|
-
const semantic = program.getSemanticDiagnostics(sourceFile);
|
|
156
|
-
|
|
157
|
-
for (const diagnostic of [...syntactic, ...semantic]) {
|
|
158
|
-
diagnostics.push(this.formatDiagnostic(diagnostic, sourceFile));
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
} catch (error) {
|
|
162
|
-
this.logger?.debug('Semantic analysis encountered error', {
|
|
163
|
-
file: filePath,
|
|
164
|
-
error: error.message
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return diagnostics;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Format TypeScript diagnostic to standard error format
|
|
173
|
-
* @private
|
|
174
|
-
*/
|
|
175
|
-
formatDiagnostic(diagnostic, sourceFile) {
|
|
176
|
-
let line = 0;
|
|
177
|
-
let column = 0;
|
|
178
|
-
|
|
179
|
-
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
180
|
-
const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
181
|
-
line = position.line + 1; // 1-indexed
|
|
182
|
-
column = position.character + 1;
|
|
183
|
-
} else if (sourceFile && diagnostic.start !== undefined) {
|
|
184
|
-
const position = sourceFile.getLineAndCharacterOfPosition(diagnostic.start);
|
|
185
|
-
line = position.line + 1;
|
|
186
|
-
column = position.character + 1;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
|
190
|
-
|
|
191
|
-
// Determine severity
|
|
192
|
-
let severity;
|
|
193
|
-
switch (diagnostic.category) {
|
|
194
|
-
case ts.DiagnosticCategory.Error:
|
|
195
|
-
severity = STATIC_ANALYSIS.SEVERITY.ERROR;
|
|
196
|
-
break;
|
|
197
|
-
case ts.DiagnosticCategory.Warning:
|
|
198
|
-
severity = STATIC_ANALYSIS.SEVERITY.WARNING;
|
|
199
|
-
break;
|
|
200
|
-
case ts.DiagnosticCategory.Message:
|
|
201
|
-
case ts.DiagnosticCategory.Suggestion:
|
|
202
|
-
severity = STATIC_ANALYSIS.SEVERITY.INFO;
|
|
203
|
-
break;
|
|
204
|
-
default:
|
|
205
|
-
severity = STATIC_ANALYSIS.SEVERITY.ERROR;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Determine category based on error code and message
|
|
209
|
-
let category = STATIC_ANALYSIS.CATEGORY.SYNTAX;
|
|
210
|
-
const code = diagnostic.code;
|
|
211
|
-
|
|
212
|
-
// Categorize based on error code ranges
|
|
213
|
-
if (code >= 2000 && code < 3000) {
|
|
214
|
-
category = STATIC_ANALYSIS.CATEGORY.TYPE;
|
|
215
|
-
} else if (code >= 1000 && code < 2000) {
|
|
216
|
-
category = STATIC_ANALYSIS.CATEGORY.SYNTAX;
|
|
217
|
-
} else if (code >= 2300 && code < 2400) {
|
|
218
|
-
category = STATIC_ANALYSIS.CATEGORY.IMPORT;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Check message content for more specific categorization
|
|
222
|
-
const lowerMessage = message.toLowerCase();
|
|
223
|
-
if (lowerMessage.includes('cannot find module') ||
|
|
224
|
-
lowerMessage.includes('import') ||
|
|
225
|
-
lowerMessage.includes('export')) {
|
|
226
|
-
category = STATIC_ANALYSIS.CATEGORY.IMPORT;
|
|
227
|
-
} else if (lowerMessage.includes('type') ||
|
|
228
|
-
lowerMessage.includes('interface') ||
|
|
229
|
-
lowerMessage.includes('class')) {
|
|
230
|
-
category = STATIC_ANALYSIS.CATEGORY.TYPE;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return {
|
|
234
|
-
file: diagnostic.file?.fileName || sourceFile?.fileName || 'unknown',
|
|
235
|
-
line,
|
|
236
|
-
column,
|
|
237
|
-
severity,
|
|
238
|
-
rule: `TS${code}`,
|
|
239
|
-
message,
|
|
240
|
-
category,
|
|
241
|
-
fixable: false, // TypeScript doesn't provide fix information easily
|
|
242
|
-
code: diagnostic.code
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export default TypeScriptAnalyzer;
|
|
1
|
+
function a0_0x39c8(_0x5517ac,_0x3be3e9){_0x5517ac=_0x5517ac-0x126;const _0x3c057e=a0_0x3c05();let _0x39c8e8=_0x3c057e[_0x5517ac];if(a0_0x39c8['APTWGa']===undefined){var _0x3ededf=function(_0x5b99d6){const _0x4c7d25='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x48ea15='',_0x20f027='';for(let _0x572658=0x0,_0x29897e,_0x307dd6,_0x381925=0x0;_0x307dd6=_0x5b99d6['charAt'](_0x381925++);~_0x307dd6&&(_0x29897e=_0x572658%0x4?_0x29897e*0x40+_0x307dd6:_0x307dd6,_0x572658++%0x4)?_0x48ea15+=String['fromCharCode'](0xff&_0x29897e>>(-0x2*_0x572658&0x6)):0x0){_0x307dd6=_0x4c7d25['indexOf'](_0x307dd6);}for(let _0x344550=0x0,_0x28ff94=_0x48ea15['length'];_0x344550<_0x28ff94;_0x344550++){_0x20f027+='%'+('00'+_0x48ea15['charCodeAt'](_0x344550)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x20f027);};a0_0x39c8['DTLOku']=_0x3ededf,a0_0x39c8['wFLwju']={},a0_0x39c8['APTWGa']=!![];}const _0x44800e=_0x3c057e[0x0],_0x3e7463=_0x5517ac+_0x44800e,_0x24c007=a0_0x39c8['wFLwju'][_0x3e7463];return!_0x24c007?(_0x39c8e8=a0_0x39c8['DTLOku'](_0x39c8e8),a0_0x39c8['wFLwju'][_0x3e7463]=_0x39c8e8):_0x39c8e8=_0x24c007,_0x39c8e8;}const a0_0x71f7c=a0_0x39c8;function a0_0x3c05(){const _0x103934=['BgvUz3rO','y3jLyxrLu291CMnLrMLSzq','mty0mduYn3jfsvPbtG','y2fUBM90igzPBMqGBw9KDwXL','zM9YBwf0rgLHz25VC3rPyW','nJGWntu4sg9oCgHh','CgfYC2veAwfNBM9ZDgLJCW','yw5HBhL6zq','mLLXt3bcza','mJCZntG0nffNDfb0vq','u1Lovefy','uMvHy3q','mte1odbuu2n0uMW','vhLWzvnJCMLWDcbHBMfSExnPCYbMywLSzwq','mtyWnJi1me5qrKr4CW','y2HHCMfJDgvY','ChvZAa','mJG5mgfIs3PTra','u3vNz2vZDgLVBG','qw5HBhLZAxmGzMfPBgvKoIa','rgLHz25VC3rPy0nHDgvNB3j5','Bg9Nz2vY','BwvZC2fNzq','v2fYBMLUzW','tw9KDwXLs2LUza','zgvIDwC','C2v2zxjPDhK','v0fstKLorW','mZjpEfDor1C','u2nYAxb0vgfYz2v0','mtm3nZi2mdf5tKniu20','rvnozxH0','zMLSzu5HBwu','tM9KzuPZ','u0vwrvjjvfK','C3rHCNq','vhLWzvnJCMLWDcbHBMfSExnPCYbJB21WBgv0zwq','z2v0u2vTyw50AwneAwfNBM9ZDgLJCW','ndmYmta3n2Hyz3LesG','Aw5JBhvKzxm','y2XHC3m','tw9KDwXLuMvZB2X1DgLVBKTPBMq','zMLSzq','q0furuDpuLK','z2v0tgLUzufUzenOyxjHy3rLCK9Mug9ZAxrPB24','zMLSDgvY','Dg9mB3DLCKnHC2u','rvjst1i','su5gtW'];a0_0x3c05=function(){return _0x103934;};return a0_0x3c05();}(function(_0x1f3a4c,_0x431f0c){const _0x23e43d=a0_0x39c8,_0x5774f0=_0x1f3a4c();while(!![]){try{const _0x3a5db7=parseInt(_0x23e43d(0x14f))/0x1*(parseInt(_0x23e43d(0x14c))/0x2)+-parseInt(_0x23e43d(0x13c))/0x3+-parseInt(_0x23e43d(0x153))/0x4*(-parseInt(_0x23e43d(0x127))/0x5)+parseInt(_0x23e43d(0x150))/0x6+-parseInt(_0x23e43d(0x149))/0x7*(-parseInt(_0x23e43d(0x132))/0x8)+-parseInt(_0x23e43d(0x134))/0x9+parseInt(_0x23e43d(0x155))/0xa;if(_0x3a5db7===_0x431f0c)break;else _0x5774f0['push'](_0x5774f0['shift']());}catch(_0x19f703){_0x5774f0['push'](_0x5774f0['shift']());}}}(a0_0x3c05,0xe4d2f));import a0_0x48ea15 from'typescript';import a0_0x20f027 from'path';import{STATIC_ANALYSIS}from'../utilities/constants.js';class TypeScriptAnalyzer{constructor(_0x572658=null){const _0x831d3=a0_0x39c8;this[_0x831d3(0x12b)]=_0x572658,this['compilerOptions']={'noEmit':!![],'jsx':a0_0x48ea15['JsxEmit'][_0x831d3(0x152)],'target':a0_0x48ea15['ScriptTarget']['Latest'],'module':a0_0x48ea15[_0x831d3(0x12e)][_0x831d3(0x135)],'moduleResolution':a0_0x48ea15[_0x831d3(0x13f)][_0x831d3(0x137)],'esModuleInterop':!![],'skipLibCheck':!![],'strict':!![],'noImplicitAny':!![],'strictNullChecks':!![],'strictFunctionTypes':!![],'allowJs':![]};}async[a0_0x71f7c(0x14e)](_0x29897e,_0x307dd6,_0x381925={}){const _0x478a6e=a0_0x71f7c;try{const _0x344550=[],_0x28ff94=a0_0x48ea15[_0x478a6e(0x148)](_0x29897e,_0x307dd6,a0_0x48ea15[_0x478a6e(0x133)]['Latest'],!![]),_0x12aca9=this['getSyntacticDiagnostics'](_0x28ff94);_0x344550['push'](..._0x12aca9);const _0x4bbe01=await this['getSemanticDiagnostics'](_0x29897e,_0x307dd6);return _0x344550[_0x478a6e(0x126)](..._0x4bbe01),this[_0x478a6e(0x12b)]?.[_0x478a6e(0x12f)](_0x478a6e(0x13a),{'file':_0x29897e,'totalDiagnostics':_0x344550[_0x478a6e(0x147)],'errors':_0x344550[_0x478a6e(0x143)](_0x528e11=>_0x528e11[_0x478a6e(0x130)]===STATIC_ANALYSIS['SEVERITY'][_0x478a6e(0x145)])[_0x478a6e(0x147)],'warnings':_0x344550['filter'](_0x34c759=>_0x34c759['severity']===STATIC_ANALYSIS[_0x478a6e(0x138)][_0x478a6e(0x131)])['length']}),_0x344550;}catch(_0xd64278){return this[_0x478a6e(0x12b)]?.['error'](_0x478a6e(0x154),{'file':_0x29897e,'error':_0xd64278[_0x478a6e(0x12c)]}),[{'file':_0x29897e,'line':0x0,'column':0x0,'severity':STATIC_ANALYSIS['SEVERITY'][_0x478a6e(0x145)],'rule':'analyzer-error','message':_0x478a6e(0x129)+_0xd64278['message'],'category':STATIC_ANALYSIS['CATEGORY'][_0x478a6e(0x151)]}];}}['getSyntacticDiagnostics'](_0x242932){const _0x49e670=a0_0x71f7c,_0x1d9ba9=[];if(_0x242932[_0x49e670(0x14d)]&&_0x242932[_0x49e670(0x14d)]['length']>0x0)for(const _0x180a11 of _0x242932[_0x49e670(0x14d)]){_0x1d9ba9['push'](this[_0x49e670(0x14b)](_0x180a11,_0x242932));}return _0x1d9ba9;}async[a0_0x71f7c(0x13b)](_0x441d77,_0x400eff){const _0x3af2b2=a0_0x71f7c,_0x5d5eaa=[];try{const _0x1bda1a=a0_0x48ea15['createSourceFile'](_0x441d77,_0x400eff,a0_0x48ea15[_0x3af2b2(0x133)]['Latest'],!![]),_0x142f24={'getSourceFile':_0x3d53a0=>{if(_0x3d53a0===_0x441d77)return _0x1bda1a;return undefined;},'getDefaultLibFileName':()=>'lib.d.ts','writeFile':()=>{},'getCurrentDirectory':()=>a0_0x20f027['dirname'](_0x441d77),'getDirectories':()=>[],'fileExists':_0x4bb72c=>_0x4bb72c===_0x441d77,'readFile':_0x589722=>{if(_0x589722===_0x441d77)return _0x400eff;return undefined;},'getCanonicalFileName':_0xdec5cb=>_0xdec5cb,'useCaseSensitiveFileNames':()=>!![],'getNewLine':()=>'\x0a'},_0x3a0cd4=a0_0x48ea15['createProgram']({'rootNames':[_0x441d77],'options':this['compilerOptions'],'host':_0x142f24}),_0x1a7265=_0x3a0cd4['getSyntacticDiagnostics'](_0x1bda1a),_0x37bafa=_0x3a0cd4['getSemanticDiagnostics'](_0x1bda1a);for(const _0x3fa854 of[..._0x1a7265,..._0x37bafa]){_0x5d5eaa['push'](this['formatDiagnostic'](_0x3fa854,_0x1bda1a));}}catch(_0x209867){this[_0x3af2b2(0x12b)]?.['debug']('Semantic\x20analysis\x20encountered\x20error',{'file':_0x441d77,'error':_0x209867[_0x3af2b2(0x12c)]});}return _0x5d5eaa;}['formatDiagnostic'](_0x11fbf0,_0x70900){const _0x203145=a0_0x71f7c;let _0xb546d6=0x0,_0x238463=0x0;if(_0x11fbf0[_0x203145(0x140)]&&_0x11fbf0['start']!==undefined){const _0x2aeca0=_0x11fbf0['file'][_0x203145(0x142)](_0x11fbf0['start']);_0xb546d6=_0x2aeca0['line']+0x1,_0x238463=_0x2aeca0[_0x203145(0x156)]+0x1;}else{if(_0x70900&&_0x11fbf0['start']!==undefined){const _0x247de2=_0x70900[_0x203145(0x142)](_0x11fbf0[_0x203145(0x139)]);_0xb546d6=_0x247de2['line']+0x1,_0x238463=_0x247de2[_0x203145(0x156)]+0x1;}}const _0x31cadf=a0_0x48ea15['flattenDiagnosticMessageText'](_0x11fbf0['messageText'],'\x0a');let _0x50e987;switch(_0x11fbf0['category']){case a0_0x48ea15[_0x203145(0x12a)]['Error']:_0x50e987=STATIC_ANALYSIS[_0x203145(0x138)]['ERROR'];break;case a0_0x48ea15[_0x203145(0x12a)][_0x203145(0x12d)]:_0x50e987=STATIC_ANALYSIS['SEVERITY'][_0x203145(0x131)];break;case a0_0x48ea15['DiagnosticCategory']['Message']:case a0_0x48ea15['DiagnosticCategory'][_0x203145(0x128)]:_0x50e987=STATIC_ANALYSIS['SEVERITY'][_0x203145(0x146)];break;default:_0x50e987=STATIC_ANALYSIS[_0x203145(0x138)]['ERROR'];}let _0x2eff39=STATIC_ANALYSIS['CATEGORY']['SYNTAX'];const _0x1e59c2=_0x11fbf0['code'];if(_0x1e59c2>=0x7d0&&_0x1e59c2<0xbb8)_0x2eff39=STATIC_ANALYSIS[_0x203145(0x141)]['TYPE'];else{if(_0x1e59c2>=0x3e8&&_0x1e59c2<0x7d0)_0x2eff39=STATIC_ANALYSIS['CATEGORY']['SYNTAX'];else _0x1e59c2>=0x8fc&&_0x1e59c2<0x960&&(_0x2eff39=STATIC_ANALYSIS[_0x203145(0x141)]['IMPORT']);}const _0x2604f5=_0x31cadf[_0x203145(0x144)]();if(_0x2604f5[_0x203145(0x13d)](_0x203145(0x14a))||_0x2604f5[_0x203145(0x13d)]('import')||_0x2604f5[_0x203145(0x13d)]('export'))_0x2eff39=STATIC_ANALYSIS['CATEGORY']['IMPORT'];else(_0x2604f5[_0x203145(0x13d)]('type')||_0x2604f5[_0x203145(0x13d)]('interface')||_0x2604f5[_0x203145(0x13d)](_0x203145(0x13e)))&&(_0x2eff39=STATIC_ANALYSIS['CATEGORY']['TYPE']);return{'file':_0x11fbf0[_0x203145(0x140)]?.['fileName']||_0x70900?.[_0x203145(0x136)]||'unknown','line':_0xb546d6,'column':_0x238463,'severity':_0x50e987,'rule':'TS'+_0x1e59c2,'message':_0x31cadf,'category':_0x2eff39,'fixable':![],'code':_0x11fbf0['code']};}}export default TypeScriptAnalyzer;
|
|
@@ -1,344 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Analyzes clones and provides refactoring recommendations
|
|
3
|
-
*/
|
|
4
|
-
export class RefactoringAnalyzer {
|
|
5
|
-
constructor(config) {
|
|
6
|
-
this.config = config;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Analyze clones and provide refactoring advice
|
|
11
|
-
* @param {Array} clones - Array of detected clones
|
|
12
|
-
* @returns {Array} Enriched clones with refactoring advice
|
|
13
|
-
*/
|
|
14
|
-
analyzeClones(clones) {
|
|
15
|
-
console.log('Analyzing clones for refactoring opportunities...');
|
|
16
|
-
|
|
17
|
-
return clones.map((clone, index) => {
|
|
18
|
-
const metrics = this.calculateMetrics(clone);
|
|
19
|
-
const advice = this.generateRefactoringAdvice(clone, metrics);
|
|
20
|
-
|
|
21
|
-
return {
|
|
22
|
-
id: `clone-${index + 1}`,
|
|
23
|
-
type: clone.type,
|
|
24
|
-
confidence: clone.confidence,
|
|
25
|
-
instances: clone.blocks.map(block => ({
|
|
26
|
-
file: block.file,
|
|
27
|
-
startLine: block.startLine,
|
|
28
|
-
endLine: block.endLine,
|
|
29
|
-
code: this.truncateCode(block.code),
|
|
30
|
-
fullCode: block.code,
|
|
31
|
-
blockType: block.type
|
|
32
|
-
})),
|
|
33
|
-
metrics,
|
|
34
|
-
refactoringAdvice: advice
|
|
35
|
-
};
|
|
36
|
-
}).sort((a, b) => b.metrics.impactScore - a.metrics.impactScore);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Calculate metrics for a clone
|
|
41
|
-
*/
|
|
42
|
-
calculateMetrics(clone) {
|
|
43
|
-
const blocks = clone.blocks;
|
|
44
|
-
const tokenCount = clone.tokenCount;
|
|
45
|
-
const lineCount = this.averageLineCount(blocks);
|
|
46
|
-
const instanceCount = blocks.length;
|
|
47
|
-
|
|
48
|
-
// Calculate impact score (higher = more important to refactor)
|
|
49
|
-
const impactScore = this.calculateImpactScore(
|
|
50
|
-
tokenCount,
|
|
51
|
-
lineCount,
|
|
52
|
-
instanceCount,
|
|
53
|
-
clone.confidence
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
// Calculate duplication overhead
|
|
57
|
-
const duplicatedLines = lineCount * (instanceCount - 1);
|
|
58
|
-
const duplicatedTokens = tokenCount * (instanceCount - 1);
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
tokenCount,
|
|
62
|
-
lineCount,
|
|
63
|
-
instanceCount,
|
|
64
|
-
duplicatedLines,
|
|
65
|
-
duplicatedTokens,
|
|
66
|
-
impactScore: parseFloat(impactScore.toFixed(2)),
|
|
67
|
-
filesCovered: new Set(blocks.map(b => b.file)).size
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Calculate impact score for prioritization
|
|
73
|
-
*/
|
|
74
|
-
calculateImpactScore(tokenCount, lineCount, instanceCount, confidence) {
|
|
75
|
-
// Weighted formula:
|
|
76
|
-
// - Size matters (more tokens = more important)
|
|
77
|
-
// - Instances matter (more copies = more important)
|
|
78
|
-
// - Confidence matters
|
|
79
|
-
// - Line count matters (user visibility)
|
|
80
|
-
|
|
81
|
-
const sizeScore = Math.log10(tokenCount + 1) * 2;
|
|
82
|
-
const instanceScore = Math.log2(instanceCount + 1) * 3;
|
|
83
|
-
const confidenceScore = confidence * 2;
|
|
84
|
-
const lineScore = Math.min(lineCount / 10, 3);
|
|
85
|
-
|
|
86
|
-
return sizeScore + instanceScore + confidenceScore + lineScore;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Generate refactoring advice
|
|
91
|
-
*/
|
|
92
|
-
generateRefactoringAdvice(clone, metrics) {
|
|
93
|
-
const strategy = this.determineRefactoringStrategy(clone, metrics);
|
|
94
|
-
const priority = this.determinePriority(metrics);
|
|
95
|
-
const suggestedName = this.suggestName(clone);
|
|
96
|
-
const reasoning = this.generateReasoning(clone, metrics, strategy);
|
|
97
|
-
const estimatedEffort = this.estimateEffort(metrics, strategy);
|
|
98
|
-
const benefits = this.describeBenefits(metrics);
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
priority,
|
|
102
|
-
strategy,
|
|
103
|
-
suggestedName,
|
|
104
|
-
reasoning,
|
|
105
|
-
estimatedEffort,
|
|
106
|
-
benefits,
|
|
107
|
-
actionableSteps: this.generateActionableSteps(strategy, suggestedName, metrics)
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Determine refactoring strategy
|
|
113
|
-
*/
|
|
114
|
-
determineRefactoringStrategy(clone, metrics) {
|
|
115
|
-
const { tokenCount, lineCount, instanceCount, filesCovered } = metrics;
|
|
116
|
-
const blockTypes = clone.blocks.map(b => b.type);
|
|
117
|
-
|
|
118
|
-
// Check if it's a function/method
|
|
119
|
-
const isFunctionLike = blockTypes.some(type =>
|
|
120
|
-
type.includes('Function') || type.includes('Method')
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
// Check if it's a class
|
|
124
|
-
const isClassLike = blockTypes.some(type =>
|
|
125
|
-
type.includes('Class')
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
// Decision tree
|
|
129
|
-
if (isClassLike && lineCount > 50) {
|
|
130
|
-
return 'extract-module';
|
|
131
|
-
} else if (filesCovered > 2 && tokenCount > 100) {
|
|
132
|
-
return 'extract-module';
|
|
133
|
-
} else if (isFunctionLike || (lineCount >= 10 && lineCount <= 50)) {
|
|
134
|
-
return 'extract-function';
|
|
135
|
-
} else if (lineCount > 50) {
|
|
136
|
-
return 'extract-class';
|
|
137
|
-
} else if (lineCount < 10) {
|
|
138
|
-
return 'extract-constant-or-utility';
|
|
139
|
-
} else {
|
|
140
|
-
return 'extract-function';
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Determine priority level
|
|
146
|
-
*/
|
|
147
|
-
determinePriority(metrics) {
|
|
148
|
-
const { impactScore } = metrics;
|
|
149
|
-
|
|
150
|
-
if (impactScore >= 8) return 'high';
|
|
151
|
-
if (impactScore >= 5) return 'medium';
|
|
152
|
-
return 'low';
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Suggest a name based on code analysis
|
|
157
|
-
*/
|
|
158
|
-
suggestName(clone) {
|
|
159
|
-
// Extract common words from the code
|
|
160
|
-
const allCode = clone.blocks.map(b => b.code).join(' ');
|
|
161
|
-
|
|
162
|
-
// Look for common identifiers
|
|
163
|
-
const identifiers = allCode.match(/[a-zA-Z_$][a-zA-Z0-9_$]*/g) || [];
|
|
164
|
-
const frequency = {};
|
|
165
|
-
|
|
166
|
-
identifiers.forEach(id => {
|
|
167
|
-
// Skip common keywords
|
|
168
|
-
if (['const', 'let', 'var', 'function', 'return', 'if', 'else', 'for', 'while'].includes(id)) {
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
frequency[id] = (frequency[id] || 0) + 1;
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
// Find most common meaningful identifier
|
|
175
|
-
const sorted = Object.entries(frequency)
|
|
176
|
-
.sort((a, b) => b[1] - a[1])
|
|
177
|
-
.slice(0, 3);
|
|
178
|
-
|
|
179
|
-
if (sorted.length > 0) {
|
|
180
|
-
// Create a descriptive name from top identifiers
|
|
181
|
-
const topWords = sorted.map(([word]) => word);
|
|
182
|
-
return this.createFunctionName(topWords);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return 'extractedFunction';
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Create a function name from words
|
|
190
|
-
*/
|
|
191
|
-
createFunctionName(words) {
|
|
192
|
-
if (words.length === 0) return 'extractedFunction';
|
|
193
|
-
|
|
194
|
-
// Convert to camelCase
|
|
195
|
-
return words[0] + words.slice(1).map(w =>
|
|
196
|
-
w.charAt(0).toUpperCase() + w.slice(1)
|
|
197
|
-
).join('');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Generate reasoning for refactoring
|
|
202
|
-
*/
|
|
203
|
-
generateReasoning(clone, metrics, strategy) {
|
|
204
|
-
const { instanceCount, duplicatedLines, filesCovered } = metrics;
|
|
205
|
-
|
|
206
|
-
let reasoning = `This ${clone.type} code pattern appears ${instanceCount} times`;
|
|
207
|
-
|
|
208
|
-
if (filesCovered > 1) {
|
|
209
|
-
reasoning += ` across ${filesCovered} different files`;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
reasoning += `, resulting in ${duplicatedLines} duplicated lines. `;
|
|
213
|
-
|
|
214
|
-
reasoning += `Refactoring to ${strategy.replace(/-/g, ' ')} would improve maintainability`;
|
|
215
|
-
|
|
216
|
-
if (instanceCount >= 3) {
|
|
217
|
-
reasoning += ', reduce bugs from inconsistent changes';
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
reasoning += ', and reduce code size';
|
|
221
|
-
|
|
222
|
-
if (metrics.impactScore >= 8) {
|
|
223
|
-
reasoning += '. This is a high-impact refactoring opportunity';
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return reasoning + '.';
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Estimate effort for refactoring
|
|
231
|
-
*/
|
|
232
|
-
estimateEffort(metrics, strategy) {
|
|
233
|
-
const { lineCount, instanceCount, filesCovered } = metrics;
|
|
234
|
-
|
|
235
|
-
let effortPoints = 0;
|
|
236
|
-
|
|
237
|
-
// Base effort on size
|
|
238
|
-
effortPoints += Math.min(lineCount / 10, 5);
|
|
239
|
-
|
|
240
|
-
// Effort increases with instances
|
|
241
|
-
effortPoints += instanceCount * 0.5;
|
|
242
|
-
|
|
243
|
-
// Effort increases with file spread
|
|
244
|
-
effortPoints += filesCovered * 0.5;
|
|
245
|
-
|
|
246
|
-
// Strategy-specific effort
|
|
247
|
-
if (strategy === 'extract-module') {
|
|
248
|
-
effortPoints += 3;
|
|
249
|
-
} else if (strategy === 'extract-class') {
|
|
250
|
-
effortPoints += 2;
|
|
251
|
-
} else if (strategy === 'extract-function') {
|
|
252
|
-
effortPoints += 1;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (effortPoints <= 3) return 'low';
|
|
256
|
-
if (effortPoints <= 7) return 'medium';
|
|
257
|
-
return 'high';
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Describe benefits of refactoring
|
|
262
|
-
*/
|
|
263
|
-
describeBenefits(metrics) {
|
|
264
|
-
const benefits = [];
|
|
265
|
-
|
|
266
|
-
benefits.push(`Eliminate ${metrics.duplicatedLines} duplicated lines of code`);
|
|
267
|
-
benefits.push(`Improve maintainability by centralizing logic in one place`);
|
|
268
|
-
|
|
269
|
-
if (metrics.instanceCount >= 3) {
|
|
270
|
-
benefits.push(`Reduce risk of inconsistent changes across ${metrics.instanceCount} locations`);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (metrics.filesCovered > 2) {
|
|
274
|
-
benefits.push(`Improve code organization across ${metrics.filesCovered} files`);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
benefits.push('Make future changes easier and less error-prone');
|
|
278
|
-
|
|
279
|
-
return benefits;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Generate actionable steps
|
|
284
|
-
*/
|
|
285
|
-
generateActionableSteps(strategy, suggestedName, metrics) {
|
|
286
|
-
const steps = [];
|
|
287
|
-
|
|
288
|
-
switch (strategy) {
|
|
289
|
-
case 'extract-function':
|
|
290
|
-
steps.push(`1. Create a new function named '${suggestedName}'`);
|
|
291
|
-
steps.push('2. Move the duplicated logic into this function');
|
|
292
|
-
steps.push('3. Identify parameters needed from the surrounding context');
|
|
293
|
-
steps.push('4. Replace all instances with calls to the new function');
|
|
294
|
-
steps.push('5. Test to ensure behavior is preserved');
|
|
295
|
-
break;
|
|
296
|
-
|
|
297
|
-
case 'extract-class':
|
|
298
|
-
steps.push(`1. Create a new class to encapsulate this functionality`);
|
|
299
|
-
steps.push('2. Move related methods and properties into the class');
|
|
300
|
-
steps.push('3. Update all instances to use the new class');
|
|
301
|
-
steps.push('4. Consider dependency injection for better testability');
|
|
302
|
-
break;
|
|
303
|
-
|
|
304
|
-
case 'extract-module':
|
|
305
|
-
steps.push(`1. Create a new module/file for this shared functionality`);
|
|
306
|
-
steps.push('2. Move the duplicated code into the new module');
|
|
307
|
-
steps.push('3. Export the necessary functions/classes');
|
|
308
|
-
steps.push('4. Update all files to import from the new module');
|
|
309
|
-
steps.push('5. Update any build configurations if needed');
|
|
310
|
-
break;
|
|
311
|
-
|
|
312
|
-
default:
|
|
313
|
-
steps.push(`1. Extract the duplicated code using ${strategy.replace(/-/g, ' ')}`);
|
|
314
|
-
steps.push('2. Replace all instances with the extracted version');
|
|
315
|
-
steps.push('3. Test thoroughly');
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
return steps;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Truncate code for display
|
|
323
|
-
*/
|
|
324
|
-
truncateCode(code, maxLines = 10) {
|
|
325
|
-
const lines = code.split('\n');
|
|
326
|
-
|
|
327
|
-
if (lines.length <= maxLines) {
|
|
328
|
-
return code;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return lines.slice(0, maxLines).join('\n') + '\n... (truncated)';
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Calculate average line count
|
|
336
|
-
*/
|
|
337
|
-
averageLineCount(blocks) {
|
|
338
|
-
const totalLines = blocks.reduce((sum, block) =>
|
|
339
|
-
sum + (block.endLine - block.startLine + 1), 0
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
return Math.round(totalLines / blocks.length);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
1
|
+
const a0_0x164b82=a0_0x1d5a;function a0_0xf1c8(){const _0x4c02bc=['zwXZzq','zxH0CMfJDc1JBgfZCW','y29UzMLN','CM91BMq','CMvKDwnL','sw1WCM92zsbTywLUDgfPBMfIAwXPDhKGyNKGy2vUDhjHBgL6Aw5NigXVz2LJigLUig9UzsbWBgfJzq','ms4Gq3jLyxrLigeGBMv3igz1BMn0Aw9Uig5HBwvKicC','zgv0zxjTAw5LuMvMywn0B3jPBMDtDhjHDgvNEq','C2XPy2u','mI4Gtw92zsb0AguGzhvWBgLJyxrLzcbSB2DPyYbPBNrVihrOAxmGzNvUy3rPB24','uMvMywn0B3jPBMCGDg8G','BgvUz3rO','zxH0CMfJDgvKrNvUy3rPB24','z2vUzxjHDgvby3rPB25HyMXLu3rLChm','igrPzMzLCMvUDcbMAwXLCW','mJj6u2vkr3G','zMLSzq','nhL4yLfMyq','lcbYzxn1BhrPBMCGAw4G','Dg9vChbLCKnHC2u','mI4GuMvWBgfJzsbHBgWGAw5ZDgfUy2vZihDPDgGGDgHLigv4DhjHy3rLzcb2zxjZAw9U','mZyYmdK2nePqsLHLsG','Bg9NmG','zxn0Aw1HDgvfzMzVCNq','mJi3mZiXnxnSu2rZBG','otu4mti4rffhvKvn','ignVzguGCgf0DgvYBIbHChbLyxjZia','ndvRChPiq3u','CMvWBgfJzq','zhvWBgLJyxrLzeXPBMvZ','Aw5JBhvKzxm','y29UzMLKzw5Jzq','zxH0CMfJDc1TB2r1Bgu','zM9Y','mJzRC3PXCNy','yMXVy2TZ','zNvUy3rPB24','vgHPCYa','yw5HBhL6zunSB25LCW','zxH0CMfJDc1MDw5JDgLVBG','Dg9Rzw5dB3vUDa','zw5KtgLUzq','sw1WCM92zsbJB2rLig9Yz2fUAxPHDgLVBIbHy3jVC3mG','ChvZAa','zMLSzxndB3zLCMvK','C3rHCNrmAw5L','ndqXmZC5meXysMH1rG','AgLNAa','rNvUy3rPB24','AM9PBG','CMv0DxjU','zxH0CMfJDc1JB25ZDgfUDc1VCI11DgLSAxr5','BwfW','y2HHCKf0','mtC3mda2m0TqzgvJvG','q2XHC3m','igzPBgvZ','nc4GuMvWBgfJzsbHBgWGAw5ZDgfUy2vZihDPDgGGy2fSBhmGDg8GDgHLig5LDYbMDw5JDgLVBG','nJaYrhbcthnP','ns4GvgvZDcb0BYbLBNn1CMuGyMvOyxzPB3iGAxmGChjLC2vYDMvK','D2HPBgu','DhLWzq','ms4Gq3jLyxrLigeGBMv3ig1VzhvSzs9MAwXLigzVCIb0AgLZihnOyxjLzcbMDw5JDgLVBMfSAxr5','zw50CMLLCW','C29YDa','lIbuAgLZigLZigeGAgLNAc1PBxbHy3qGCMvMywn0B3jPBMCGB3bWB3j0Dw5PDhK','ms4GrxH0CMfJDcb0AguGzhvWBgLJyxrLzcbJB2rLihvZAw5Nia','y2fSy3vSyxrLtwv0CMLJCW','y2fSy3vSyxrLsw1Wywn0u2nVCMu','otyXogPwwgLfrG','y29Kzq','BwvKAxvT','igXVy2f0Aw9UCW','y3jLyxrLrNvUy3rPB25oyw1L','ns4GvxbKyxrLigfUEsbIDwLSzcbJB25MAwD1CMf0Aw9UCYbPzIbUzwvKzwq','mY4GvgvZDcb0Ag9YB3vNAgX5','BwLU','zgv0zxjTAw5LuhjPB3jPDhK','mY4GrxHWB3j0ihrOzsbUzwnLC3nHCNKGzNvUy3rPB25Zl2nSyxnZzxm','nc4Gq29UC2LKzxiGzgvWzw5Kzw5JEsbPBMPLy3rPB24GzM9YigjLDhrLCIb0zxn0ywjPBgL0Eq','nLzTqu1dtq','zM9YrwfJAa','y29UC3q','mtuZnZu5z05LBe5u','Aw5ZDgfUy2vdB3vUDa'];a0_0xf1c8=function(){return _0x4c02bc;};return a0_0xf1c8();}function a0_0x1d5a(_0x5c52f6,_0x1dabc6){_0x5c52f6=_0x5c52f6-0x17f;const _0xf1c8ee=a0_0xf1c8();let _0x1d5a19=_0xf1c8ee[_0x5c52f6];if(a0_0x1d5a['okULOc']===undefined){var _0xc52617=function(_0x163aed){const _0x1791d4='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x30c4ac='',_0x49707b='';for(let _0x51be9b=0x0,_0x2a8a8a,_0x5bba0f,_0x1386a6=0x0;_0x5bba0f=_0x163aed['charAt'](_0x1386a6++);~_0x5bba0f&&(_0x2a8a8a=_0x51be9b%0x4?_0x2a8a8a*0x40+_0x5bba0f:_0x5bba0f,_0x51be9b++%0x4)?_0x30c4ac+=String['fromCharCode'](0xff&_0x2a8a8a>>(-0x2*_0x51be9b&0x6)):0x0){_0x5bba0f=_0x1791d4['indexOf'](_0x5bba0f);}for(let _0x262e88=0x0,_0x26e6b=_0x30c4ac['length'];_0x262e88<_0x26e6b;_0x262e88++){_0x49707b+='%'+('00'+_0x30c4ac['charCodeAt'](_0x262e88)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x49707b);};a0_0x1d5a['bHpMMt']=_0xc52617,a0_0x1d5a['AAEeAu']={},a0_0x1d5a['okULOc']=!![];}const _0x27ee63=_0xf1c8ee[0x0],_0xf569df=_0x5c52f6+_0x27ee63,_0x1f59fc=a0_0x1d5a['AAEeAu'][_0xf569df];return!_0x1f59fc?(_0x1d5a19=a0_0x1d5a['bHpMMt'](_0x1d5a19),a0_0x1d5a['AAEeAu'][_0xf569df]=_0x1d5a19):_0x1d5a19=_0x1f59fc,_0x1d5a19;}(function(_0x1b6ce3,_0x3f6f1d){const _0xa892af=a0_0x1d5a,_0x406ecd=_0x1b6ce3();while(!![]){try{const _0x3375fe=-parseInt(_0xa892af(0x189))/0x1*(-parseInt(_0xa892af(0x186))/0x2)+-parseInt(_0xa892af(0x1c1))/0x3*(parseInt(_0xa892af(0x19c))/0x4)+-parseInt(_0xa892af(0x1a3))/0x5+parseInt(_0xa892af(0x1d0))/0x6*(parseInt(_0xa892af(0x1c5))/0x7)+parseInt(_0xa892af(0x1a4))/0x8*(-parseInt(_0xa892af(0x1a6))/0x9)+parseInt(_0xa892af(0x1b9))/0xa*(parseInt(_0xa892af(0x19a))/0xb)+parseInt(_0xa892af(0x1a0))/0xc*(parseInt(_0xa892af(0x1ad))/0xd);if(_0x3375fe===_0x3f6f1d)break;else _0x406ecd['push'](_0x406ecd['shift']());}catch(_0x451d7f){_0x406ecd['push'](_0x406ecd['shift']());}}}(a0_0xf1c8,0x6be25));export class RefactoringAnalyzer{constructor(_0x30c4ac){const _0x34540f=a0_0x1d5a;this[_0x34540f(0x18d)]=_0x30c4ac;}[a0_0x164b82(0x1b1)](_0x49707b){const _0x2e4c2c=a0_0x164b82;return console['log']('Analyzing\x20clones\x20for\x20refactoring\x20opportunities...'),_0x49707b['map']((_0x51be9b,_0x2a8a8a)=>{const _0x495b49=a0_0x1d5a,_0x5bba0f=this['calculateMetrics'](_0x51be9b),_0x1386a6=this['generateRefactoringAdvice'](_0x51be9b,_0x5bba0f);return{'id':'clone-'+(_0x2a8a8a+0x1),'type':_0x51be9b[_0x495b49(0x1c8)],'confidence':_0x51be9b['confidence'],'instances':_0x51be9b['blocks'][_0x495b49(0x1bf)](_0x262e88=>({'file':_0x262e88[_0x495b49(0x19b)],'startLine':_0x262e88[_0x495b49(0x1b8)],'endLine':_0x262e88[_0x495b49(0x1b4)],'code':this['truncateCode'](_0x262e88['code']),'fullCode':_0x262e88[_0x495b49(0x1d1)],'blockType':_0x262e88[_0x495b49(0x1c8)]})),'metrics':_0x5bba0f,'refactoringAdvice':_0x1386a6};})[_0x2e4c2c(0x1cb)]((_0x26e6b,_0x47866b)=>_0x47866b['metrics']['impactScore']-_0x26e6b['metrics']['impactScore']);}[a0_0x164b82(0x1ce)](_0x4ebba){const _0x2ffdf4=a0_0x164b82,_0xcbbad0=_0x4ebba['blocks'],_0x5de019=_0x4ebba[_0x2ffdf4(0x1b3)],_0x427724=this['averageLineCount'](_0xcbbad0),_0x580332=_0xcbbad0['length'],_0xd2b6c5=this[_0x2ffdf4(0x1cf)](_0x5de019,_0x427724,_0x580332,_0x4ebba[_0x2ffdf4(0x1aa)]),_0x217b3b=_0x427724*(_0x580332-0x1),_0x81d041=_0x5de019*(_0x580332-0x1);return{'tokenCount':_0x5de019,'lineCount':_0x427724,'instanceCount':_0x580332,'duplicatedLines':_0x217b3b,'duplicatedTokens':_0x81d041,'impactScore':parseFloat(_0xd2b6c5['toFixed'](0x2)),'filesCovered':new Set(_0xcbbad0['map'](_0xccb76c=>_0xccb76c[_0x2ffdf4(0x19b)]))['size']};}['calculateImpactScore'](_0x54d25c,_0x543bc5,_0x22994c,_0x20d333){const _0x19db9d=a0_0x164b82,_0x4c30b7=Math['log10'](_0x54d25c+0x1)*0x2,_0x2dbf11=Math[_0x19db9d(0x1a1)](_0x22994c+0x1)*0x3,_0x39222c=_0x20d333*0x2,_0x5ce94=Math[_0x19db9d(0x182)](_0x543bc5/0xa,0x3);return _0x4c30b7+_0x2dbf11+_0x39222c+_0x5ce94;}['generateRefactoringAdvice'](_0x138a0c,_0x1be109){const _0x24b673=a0_0x164b82,_0xddd05e=this[_0x24b673(0x192)](_0x138a0c,_0x1be109),_0x167b37=this[_0x24b673(0x183)](_0x1be109),_0x2ce989=this['suggestName'](_0x138a0c),_0x1b1251=this['generateReasoning'](_0x138a0c,_0x1be109,_0xddd05e),_0x120ec0=this[_0x24b673(0x1a2)](_0x1be109,_0xddd05e),_0x54c951=this['describeBenefits'](_0x1be109);return{'priority':_0x167b37,'strategy':_0xddd05e,'suggestedName':_0x2ce989,'reasoning':_0x1b1251,'estimatedEffort':_0x120ec0,'benefits':_0x54c951,'actionableSteps':this[_0x24b673(0x198)](_0xddd05e,_0x2ce989,_0x1be109)};}['determineRefactoringStrategy'](_0x58be71,_0x2510ed){const _0x429079=a0_0x164b82,{tokenCount:_0x183b96,lineCount:_0x3fb884,instanceCount:_0x4144c3,filesCovered:_0x5de178}=_0x2510ed,_0x4ff206=_0x58be71[_0x429079(0x1ae)][_0x429079(0x1bf)](_0x146496=>_0x146496['type']),_0x21aec0=_0x4ff206['some'](_0x136d3c=>_0x136d3c['includes'](_0x429079(0x1bb))||_0x136d3c[_0x429079(0x1a9)]('Method')),_0x2d842f=_0x4ff206['some'](_0x12e644=>_0x12e644['includes'](_0x429079(0x1c2)));if(_0x2d842f&&_0x3fb884>0x32)return _0x429079(0x1ab);else{if(_0x5de178>0x2&&_0x183b96>0x64)return'extract-module';else{if(_0x21aec0||_0x3fb884>=0xa&&_0x3fb884<=0x32)return'extract-function';else{if(_0x3fb884>0x32)return _0x429079(0x18c);else return _0x3fb884<0xa?_0x429079(0x1be):'extract-function';}}}}['determinePriority'](_0x267d40){const _0x572805=a0_0x164b82,{impactScore:_0x5dc143}=_0x267d40;if(_0x5dc143>=0x8)return'high';if(_0x5dc143>=0x5)return _0x572805(0x1d2);return'low';}['suggestName'](_0x2a7c86){const _0x403951=a0_0x164b82,_0x5d3676=_0x2a7c86['blocks'][_0x403951(0x1bf)](_0x941eb7=>_0x941eb7['code'])[_0x403951(0x1bc)]('\x20'),_0x48a958=_0x5d3676['match'](/[a-zA-Z_$][a-zA-Z0-9_$]*/g)||[],_0x276a53={};_0x48a958[_0x403951(0x187)](_0x441192=>{const _0x1847d4=_0x403951;if([_0x1847d4(0x188),'let','var',_0x1847d4(0x1af),_0x1847d4(0x1bd),'if',_0x1847d4(0x18b),_0x1847d4(0x1ac),_0x1847d4(0x1c7)][_0x1847d4(0x1a9)](_0x441192))return;_0x276a53[_0x441192]=(_0x276a53[_0x441192]||0x0)+0x1;});const _0x53cb23=Object[_0x403951(0x1ca)](_0x276a53)['sort']((_0x55314c,_0x5555c6)=>_0x5555c6[0x1]-_0x55314c[0x1])['slice'](0x0,0x3);if(_0x53cb23[_0x403951(0x196)]>0x0){const _0x2dd10c=_0x53cb23[_0x403951(0x1bf)](([_0x30ff2f])=>_0x30ff2f);return this[_0x403951(0x17f)](_0x2dd10c);}return _0x403951(0x197);}[a0_0x164b82(0x17f)](_0x1990c7){const _0x3bf771=a0_0x164b82;if(_0x1990c7[_0x3bf771(0x196)]===0x0)return'extractedFunction';return _0x1990c7[0x0]+_0x1990c7['slice'](0x1)['map'](_0x470b86=>_0x470b86[_0x3bf771(0x1c0)](0x0)[_0x3bf771(0x19e)]()+_0x470b86[_0x3bf771(0x193)](0x1))['join']('');}['generateReasoning'](_0x58a75e,_0x5d79a2,_0x1b463d){const _0x3d06e6=a0_0x164b82,{instanceCount:_0x78e9a3,duplicatedLines:_0x3075f2,filesCovered:_0x452acb}=_0x5d79a2;let _0x5a4bdc=_0x3d06e6(0x1b0)+_0x58a75e[_0x3d06e6(0x1c8)]+_0x3d06e6(0x1a5)+_0x78e9a3+'\x20times';return _0x452acb>0x1&&(_0x5a4bdc+='\x20across\x20'+_0x452acb+_0x3d06e6(0x199)),_0x5a4bdc+=_0x3d06e6(0x19d)+_0x3075f2+'\x20duplicated\x20lines.\x20',_0x5a4bdc+=_0x3d06e6(0x195)+_0x1b463d[_0x3d06e6(0x1a7)](/-/g,'\x20')+'\x20would\x20improve\x20maintainability',_0x78e9a3>=0x3&&(_0x5a4bdc+=', reduce bugs from inconsistent changes'),_0x5a4bdc+=',\x20and\x20reduce\x20code\x20size',_0x5d79a2['impactScore']>=0x8&&(_0x5a4bdc+=_0x3d06e6(0x1cc)),_0x5a4bdc+'.';}['estimateEffort'](_0x15ad60,_0x169e32){const _0x27f2ec=a0_0x164b82,{lineCount:_0x3ed051,instanceCount:_0xf59e4a,filesCovered:_0x57b0b7}=_0x15ad60;let _0x3acac4=0x0;_0x3acac4+=Math['min'](_0x3ed051/0xa,0x5),_0x3acac4+=_0xf59e4a*0.5,_0x3acac4+=_0x57b0b7*0.5;if(_0x169e32===_0x27f2ec(0x1ab))_0x3acac4+=0x3;else{if(_0x169e32===_0x27f2ec(0x18c))_0x3acac4+=0x2;else _0x169e32===_0x27f2ec(0x1b2)&&(_0x3acac4+=0x1);}if(_0x3acac4<=0x3)return'low';if(_0x3acac4<=0x7)return _0x27f2ec(0x1d2);return _0x27f2ec(0x1ba);}['describeBenefits'](_0x54464c){const _0x3257e6=a0_0x164b82,_0x1a5710=[];return _0x1a5710[_0x3257e6(0x1b6)]('Eliminate\x20'+_0x54464c[_0x3257e6(0x1a8)]+'\x20duplicated\x20lines\x20of\x20code'),_0x1a5710['push'](_0x3257e6(0x190)),_0x54464c['instanceCount']>=0x3&&_0x1a5710[_0x3257e6(0x1b6)]('Reduce\x20risk\x20of\x20inconsistent\x20changes\x20across\x20'+_0x54464c[_0x3257e6(0x18a)]+_0x3257e6(0x1d3)),_0x54464c[_0x3257e6(0x1b7)]>0x2&&_0x1a5710['push'](_0x3257e6(0x1b5)+_0x54464c[_0x3257e6(0x1b7)]+_0x3257e6(0x1c3)),_0x1a5710['push']('Make\x20future\x20changes\x20easier\x20and\x20less\x20error-prone'),_0x1a5710;}['generateActionableSteps'](_0x4103f,_0x96e853,_0x406213){const _0x12d732=a0_0x164b82,_0x48cbe4=[];switch(_0x4103f){case'extract-function':_0x48cbe4['push'](_0x12d732(0x191)+_0x96e853+'\x27'),_0x48cbe4['push'](_0x12d732(0x194)),_0x48cbe4[_0x12d732(0x1b6)]('3. Identify parameters needed from the surrounding context'),_0x48cbe4['push'](_0x12d732(0x1c4)),_0x48cbe4['push'](_0x12d732(0x1c6));break;case'extract-class':_0x48cbe4[_0x12d732(0x1b6)]('1.\x20Create\x20a\x20new\x20class\x20to\x20encapsulate\x20this\x20functionality'),_0x48cbe4['push']('2.\x20Move\x20related\x20methods\x20and\x20properties\x20into\x20the\x20class'),_0x48cbe4['push']('3.\x20Update\x20all\x20instances\x20to\x20use\x20the\x20new\x20class'),_0x48cbe4['push'](_0x12d732(0x185));break;case _0x12d732(0x1ab):_0x48cbe4['push'](_0x12d732(0x1c9)),_0x48cbe4[_0x12d732(0x1b6)]('2.\x20Move\x20the\x20duplicated\x20code\x20into\x20the\x20new\x20module'),_0x48cbe4[_0x12d732(0x1b6)](_0x12d732(0x184)),_0x48cbe4[_0x12d732(0x1b6)]('4. Update all files to import from the new module'),_0x48cbe4[_0x12d732(0x1b6)](_0x12d732(0x180));break;default:_0x48cbe4['push'](_0x12d732(0x1cd)+_0x4103f[_0x12d732(0x1a7)](/-/g,'\x20')),_0x48cbe4['push'](_0x12d732(0x19f)),_0x48cbe4['push'](_0x12d732(0x181));}return _0x48cbe4;}['truncateCode'](_0x35919f,_0x393127=0xa){const _0x516c8b=a0_0x164b82,_0x3d5a21=_0x35919f['split']('\x0a');if(_0x3d5a21[_0x516c8b(0x196)]<=_0x393127)return _0x35919f;return _0x3d5a21[_0x516c8b(0x193)](0x0,_0x393127)[_0x516c8b(0x1bc)]('\x0a')+'\x0a...\x20(truncated)';}['averageLineCount'](_0x416427){const _0x3964ea=a0_0x164b82,_0x40098f=_0x416427[_0x3964ea(0x18f)]((_0x40b075,_0x43e002)=>_0x40b075+(_0x43e002[_0x3964ea(0x1b4)]-_0x43e002['startLine']+0x1),0x0);return Math[_0x3964ea(0x18e)](_0x40098f/_0x416427[_0x3964ea(0x196)]);}}
|