@loxia-labs/loxia-autopilot-one 1.0.1

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 (80) hide show
  1. package/LICENSE +267 -0
  2. package/README.md +509 -0
  3. package/bin/cli.js +117 -0
  4. package/package.json +94 -0
  5. package/scripts/install-scanners.js +236 -0
  6. package/src/analyzers/CSSAnalyzer.js +297 -0
  7. package/src/analyzers/ConfigValidator.js +690 -0
  8. package/src/analyzers/ESLintAnalyzer.js +320 -0
  9. package/src/analyzers/JavaScriptAnalyzer.js +261 -0
  10. package/src/analyzers/PrettierFormatter.js +247 -0
  11. package/src/analyzers/PythonAnalyzer.js +266 -0
  12. package/src/analyzers/SecurityAnalyzer.js +729 -0
  13. package/src/analyzers/TypeScriptAnalyzer.js +247 -0
  14. package/src/analyzers/codeCloneDetector/analyzer.js +344 -0
  15. package/src/analyzers/codeCloneDetector/detector.js +203 -0
  16. package/src/analyzers/codeCloneDetector/index.js +160 -0
  17. package/src/analyzers/codeCloneDetector/parser.js +199 -0
  18. package/src/analyzers/codeCloneDetector/reporter.js +148 -0
  19. package/src/analyzers/codeCloneDetector/scanner.js +59 -0
  20. package/src/core/agentPool.js +1474 -0
  21. package/src/core/agentScheduler.js +2147 -0
  22. package/src/core/contextManager.js +709 -0
  23. package/src/core/messageProcessor.js +732 -0
  24. package/src/core/orchestrator.js +548 -0
  25. package/src/core/stateManager.js +877 -0
  26. package/src/index.js +631 -0
  27. package/src/interfaces/cli.js +549 -0
  28. package/src/interfaces/webServer.js +2162 -0
  29. package/src/modules/fileExplorer/controller.js +280 -0
  30. package/src/modules/fileExplorer/index.js +37 -0
  31. package/src/modules/fileExplorer/middleware.js +92 -0
  32. package/src/modules/fileExplorer/routes.js +125 -0
  33. package/src/modules/fileExplorer/types.js +44 -0
  34. package/src/services/aiService.js +1232 -0
  35. package/src/services/apiKeyManager.js +164 -0
  36. package/src/services/benchmarkService.js +366 -0
  37. package/src/services/budgetService.js +539 -0
  38. package/src/services/contextInjectionService.js +247 -0
  39. package/src/services/conversationCompactionService.js +637 -0
  40. package/src/services/errorHandler.js +810 -0
  41. package/src/services/fileAttachmentService.js +544 -0
  42. package/src/services/modelRouterService.js +366 -0
  43. package/src/services/modelsService.js +322 -0
  44. package/src/services/qualityInspector.js +796 -0
  45. package/src/services/tokenCountingService.js +536 -0
  46. package/src/tools/agentCommunicationTool.js +1344 -0
  47. package/src/tools/agentDelayTool.js +485 -0
  48. package/src/tools/asyncToolManager.js +604 -0
  49. package/src/tools/baseTool.js +800 -0
  50. package/src/tools/browserTool.js +920 -0
  51. package/src/tools/cloneDetectionTool.js +621 -0
  52. package/src/tools/dependencyResolverTool.js +1215 -0
  53. package/src/tools/fileContentReplaceTool.js +875 -0
  54. package/src/tools/fileSystemTool.js +1107 -0
  55. package/src/tools/fileTreeTool.js +853 -0
  56. package/src/tools/imageTool.js +901 -0
  57. package/src/tools/importAnalyzerTool.js +1060 -0
  58. package/src/tools/jobDoneTool.js +248 -0
  59. package/src/tools/seekTool.js +956 -0
  60. package/src/tools/staticAnalysisTool.js +1778 -0
  61. package/src/tools/taskManagerTool.js +2873 -0
  62. package/src/tools/terminalTool.js +2304 -0
  63. package/src/tools/webTool.js +1430 -0
  64. package/src/types/agent.js +519 -0
  65. package/src/types/contextReference.js +972 -0
  66. package/src/types/conversation.js +730 -0
  67. package/src/types/toolCommand.js +747 -0
  68. package/src/utilities/attachmentValidator.js +292 -0
  69. package/src/utilities/configManager.js +582 -0
  70. package/src/utilities/constants.js +722 -0
  71. package/src/utilities/directoryAccessManager.js +535 -0
  72. package/src/utilities/fileProcessor.js +307 -0
  73. package/src/utilities/logger.js +436 -0
  74. package/src/utilities/tagParser.js +1246 -0
  75. package/src/utilities/toolConstants.js +317 -0
  76. package/web-ui/build/index.html +15 -0
  77. package/web-ui/build/logo.png +0 -0
  78. package/web-ui/build/logo2.png +0 -0
  79. package/web-ui/build/static/index-CjkkcnFA.js +344 -0
  80. package/web-ui/build/static/index-Dy2bYbOa.css +1 -0
@@ -0,0 +1,320 @@
1
+ /**
2
+ * ESLintAnalyzer - JavaScript/TypeScript code style analysis using ESLint
3
+ *
4
+ * Purpose:
5
+ * - Analyze code style and quality issues
6
+ * - Detect best practice violations
7
+ * - Support auto-fix for fixable issues
8
+ * - Integration with popular ESLint configurations
9
+ */
10
+
11
+ import { ESLint } from 'eslint';
12
+ import path from 'path';
13
+ import fs from 'fs/promises';
14
+ import { STATIC_ANALYSIS } from '../utilities/constants.js';
15
+
16
+ class ESLintAnalyzer {
17
+ constructor(logger = null) {
18
+ this.logger = logger;
19
+ this.eslintCache = new Map();
20
+ }
21
+
22
+ /**
23
+ * Analyze code with ESLint
24
+ * @param {string} filePath - Path to file
25
+ * @param {string} content - File content
26
+ * @param {Object} options - Analysis options
27
+ * @returns {Promise<Array>} Array of diagnostics
28
+ */
29
+ async analyze(filePath, content, options = {}) {
30
+ try {
31
+ const eslint = await this.getESLintInstance(options);
32
+
33
+ // Analyze the code
34
+ const results = await eslint.lintText(content, {
35
+ filePath,
36
+ warnIgnored: false
37
+ });
38
+
39
+ // Format results
40
+ const diagnostics = [];
41
+
42
+ if (results && results.length > 0) {
43
+ const result = results[0];
44
+
45
+ for (const message of result.messages) {
46
+ diagnostics.push(this.formatMessage(message, filePath));
47
+ }
48
+ }
49
+
50
+ this.logger?.debug('ESLint analysis completed', {
51
+ file: filePath,
52
+ totalDiagnostics: diagnostics.length,
53
+ errors: diagnostics.filter(d => d.severity === STATIC_ANALYSIS.SEVERITY.ERROR).length,
54
+ warnings: diagnostics.filter(d => d.severity === STATIC_ANALYSIS.SEVERITY.WARNING).length
55
+ });
56
+
57
+ return diagnostics;
58
+
59
+ } catch (error) {
60
+ this.logger?.error('ESLint analysis failed', {
61
+ file: filePath,
62
+ error: error.message
63
+ });
64
+
65
+ // Return empty array on error to allow TypeScript analyzer to continue
66
+ return [];
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Auto-fix code issues
72
+ * @param {string} filePath - Path to file
73
+ * @param {string} content - File content
74
+ * @param {Object} options - Fix options
75
+ * @returns {Promise<Object>} Fixed content and changes
76
+ */
77
+ async fix(filePath, content, options = {}) {
78
+ try {
79
+ const eslint = await this.getESLintInstance({
80
+ ...options,
81
+ fix: true // Enable auto-fix
82
+ });
83
+
84
+ // Fix the code
85
+ const results = await eslint.lintText(content, {
86
+ filePath,
87
+ warnIgnored: false
88
+ });
89
+
90
+ if (results && results.length > 0) {
91
+ const result = results[0];
92
+
93
+ return {
94
+ fixed: result.output !== undefined,
95
+ content: result.output || content,
96
+ fixedCount: result.fixableErrorCount + result.fixableWarningCount,
97
+ remainingErrors: result.errorCount - result.fixableErrorCount,
98
+ remainingWarnings: result.warningCount - result.fixableWarningCount,
99
+ changes: result.output ? this.describeChanges(content, result.output) : []
100
+ };
101
+ }
102
+
103
+ return {
104
+ fixed: false,
105
+ content,
106
+ fixedCount: 0,
107
+ remainingErrors: 0,
108
+ remainingWarnings: 0,
109
+ changes: []
110
+ };
111
+
112
+ } catch (error) {
113
+ this.logger?.error('ESLint fix failed', {
114
+ file: filePath,
115
+ error: error.message
116
+ });
117
+
118
+ throw new Error(`ESLint fix failed: ${error.message}`);
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Get or create ESLint instance
124
+ * @private
125
+ */
126
+ async getESLintInstance(options = {}) {
127
+ const {
128
+ workingDir,
129
+ fix = false,
130
+ framework
131
+ } = options;
132
+
133
+ // Create ESLint instance with configuration
134
+ const eslintConfig = await this.getESLintConfig(workingDir, framework);
135
+
136
+ const eslint = new ESLint({
137
+ fix,
138
+ useEslintrc: true, // Use .eslintrc if available
139
+ overrideConfig: eslintConfig,
140
+ errorOnUnmatchedPattern: false
141
+ });
142
+
143
+ return eslint;
144
+ }
145
+
146
+ /**
147
+ * Get ESLint configuration
148
+ * @private
149
+ */
150
+ async getESLintConfig(workingDir, framework) {
151
+ // Base configuration
152
+ const config = {
153
+ env: {
154
+ browser: true,
155
+ es2021: true,
156
+ node: true
157
+ },
158
+ parserOptions: {
159
+ ecmaVersion: 'latest',
160
+ sourceType: 'module'
161
+ },
162
+ rules: {
163
+ // Common rules
164
+ 'no-unused-vars': 'warn',
165
+ 'no-undef': 'error',
166
+ 'no-console': 'off',
167
+ 'semi': ['warn', 'always'],
168
+ 'quotes': ['warn', 'single', { avoidEscape: true }]
169
+ }
170
+ };
171
+
172
+ // Framework-specific configurations
173
+ if (framework === 'react') {
174
+ config.extends = ['eslint:recommended'];
175
+ config.parserOptions.ecmaFeatures = { jsx: true };
176
+ config.settings = {
177
+ react: {
178
+ version: 'detect'
179
+ }
180
+ };
181
+ } else if (framework === 'vue') {
182
+ config.extends = ['eslint:recommended'];
183
+ } else {
184
+ config.extends = ['eslint:recommended'];
185
+ }
186
+
187
+ // Try to detect and use project's ESLint config
188
+ if (workingDir) {
189
+ const configFiles = [
190
+ '.eslintrc.js',
191
+ '.eslintrc.cjs',
192
+ '.eslintrc.json',
193
+ 'eslint.config.js'
194
+ ];
195
+
196
+ for (const configFile of configFiles) {
197
+ try {
198
+ const configPath = path.join(workingDir, configFile);
199
+ await fs.access(configPath);
200
+ this.logger?.debug('Found ESLint config', { configFile });
201
+ // If config exists, let ESLint use it via useEslintrc
202
+ return {}; // Return empty config to let ESLint use the file
203
+ } catch {
204
+ // Config file doesn't exist, continue
205
+ }
206
+ }
207
+ }
208
+
209
+ return config;
210
+ }
211
+
212
+ /**
213
+ * Format ESLint message to standard diagnostic format
214
+ * @private
215
+ */
216
+ formatMessage(message, filePath) {
217
+ return {
218
+ file: filePath,
219
+ line: message.line || 1,
220
+ column: message.column || 1,
221
+ endLine: message.endLine,
222
+ endColumn: message.endColumn,
223
+ severity: message.severity === 2
224
+ ? STATIC_ANALYSIS.SEVERITY.ERROR
225
+ : STATIC_ANALYSIS.SEVERITY.WARNING,
226
+ rule: message.ruleId || 'eslint',
227
+ message: message.message,
228
+ category: this.categorizeRule(message.ruleId),
229
+ fixable: message.fix !== undefined,
230
+ source: 'eslint'
231
+ };
232
+ }
233
+
234
+ /**
235
+ * Categorize ESLint rule into error category
236
+ * @private
237
+ */
238
+ categorizeRule(ruleId) {
239
+ if (!ruleId) return STATIC_ANALYSIS.CATEGORY.STYLE;
240
+
241
+ // Security rules
242
+ if (ruleId.includes('security') ||
243
+ ruleId.includes('xss') ||
244
+ ruleId === 'no-eval' ||
245
+ ruleId === 'no-implied-eval') {
246
+ return STATIC_ANALYSIS.CATEGORY.SECURITY;
247
+ }
248
+
249
+ // Performance rules
250
+ if (ruleId.includes('performance') ||
251
+ ruleId === 'no-await-in-loop' ||
252
+ ruleId === 'prefer-promise-reject-errors') {
253
+ return STATIC_ANALYSIS.CATEGORY.PERFORMANCE;
254
+ }
255
+
256
+ // Import rules
257
+ if (ruleId.includes('import') ||
258
+ ruleId === 'no-undef') {
259
+ return STATIC_ANALYSIS.CATEGORY.IMPORT;
260
+ }
261
+
262
+ // Best practice rules
263
+ if (ruleId.includes('best-practices') ||
264
+ ruleId === 'no-unused-vars' ||
265
+ ruleId === 'no-unreachable' ||
266
+ ruleId === 'no-var') {
267
+ return STATIC_ANALYSIS.CATEGORY.BEST_PRACTICE;
268
+ }
269
+
270
+ // Default to style
271
+ return STATIC_ANALYSIS.CATEGORY.STYLE;
272
+ }
273
+
274
+ /**
275
+ * Describe changes made by auto-fix
276
+ * @private
277
+ */
278
+ describeChanges(original, fixed) {
279
+ const changes = [];
280
+ const originalLines = original.split('\n');
281
+ const fixedLines = fixed.split('\n');
282
+
283
+ // Simple diff - compare line by line
284
+ const maxLines = Math.max(originalLines.length, fixedLines.length);
285
+
286
+ for (let i = 0; i < maxLines; i++) {
287
+ const origLine = originalLines[i] || '';
288
+ const fixedLine = fixedLines[i] || '';
289
+
290
+ if (origLine !== fixedLine) {
291
+ changes.push({
292
+ line: i + 1,
293
+ type: origLine && fixedLine ? 'modified' : (origLine ? 'removed' : 'added'),
294
+ original: origLine,
295
+ fixed: fixedLine
296
+ });
297
+ }
298
+ }
299
+
300
+ return changes;
301
+ }
302
+
303
+ /**
304
+ * Get supported file extensions
305
+ * @returns {Array<string>} Array of supported extensions
306
+ */
307
+ getSupportedExtensions() {
308
+ return ['.js', '.jsx', '.mjs', '.cjs'];
309
+ }
310
+
311
+ /**
312
+ * Check if auto-fix is supported
313
+ * @returns {boolean} True if auto-fix is supported
314
+ */
315
+ supportsAutoFix() {
316
+ return true;
317
+ }
318
+ }
319
+
320
+ export default ESLintAnalyzer;
@@ -0,0 +1,261 @@
1
+ /**
2
+ * JavaScriptAnalyzer - Analyze JavaScript files for errors using TypeScript Compiler API
3
+ *
4
+ * Purpose:
5
+ * - Analyze JavaScript files for syntax, type, and semantic errors
6
+ * - Use TypeScript Compiler API with allowJs for JavaScript analysis
7
+ * - Provide detailed error information with line numbers
8
+ * - Support JSX syntax
9
+ */
10
+
11
+ import ts from 'typescript';
12
+ import path from 'path';
13
+ import { STATIC_ANALYSIS } from '../utilities/constants.js';
14
+
15
+ class JavaScriptAnalyzer {
16
+ constructor(logger = null) {
17
+ this.logger = logger;
18
+ this.compilerOptions = {
19
+ allowJs: true,
20
+ checkJs: true,
21
+ noEmit: true,
22
+ jsx: ts.JsxEmit.React,
23
+ target: ts.ScriptTarget.Latest,
24
+ module: ts.ModuleKind.ESNext,
25
+ moduleResolution: ts.ModuleResolutionKind.NodeJs,
26
+ esModuleInterop: true,
27
+ skipLibCheck: true,
28
+ strict: false, // Don't be too strict for JavaScript
29
+ noImplicitAny: false // Allow implicit any in JavaScript
30
+ };
31
+ }
32
+
33
+ /**
34
+ * Analyze JavaScript file for errors
35
+ * @param {string} filePath - Path to file
36
+ * @param {string} content - File content
37
+ * @param {Object} options - Analysis options
38
+ * @returns {Promise<Array>} Array of diagnostic errors
39
+ */
40
+ async analyze(filePath, content, options = {}) {
41
+ try {
42
+ const diagnostics = [];
43
+
44
+ // Create in-memory source file
45
+ const sourceFile = ts.createSourceFile(
46
+ filePath,
47
+ content,
48
+ ts.ScriptTarget.Latest,
49
+ true // setParentNodes
50
+ );
51
+
52
+ // Get syntactic diagnostics (syntax errors)
53
+ const syntacticDiagnostics = this.getSyntacticDiagnostics(sourceFile);
54
+ diagnostics.push(...syntacticDiagnostics);
55
+
56
+ // Get semantic diagnostics (type errors, undefined variables, etc.)
57
+ // For JavaScript, semantic analysis is limited but still useful
58
+ const semanticDiagnostics = await this.getSemanticDiagnostics(filePath, content);
59
+ diagnostics.push(...semanticDiagnostics);
60
+
61
+ this.logger?.debug('JavaScript 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('JavaScript 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
+ // Walk the AST to find syntax errors
96
+ const visit = (node) => {
97
+ // Check for syntax errors
98
+ if (node.kind === ts.SyntaxKind.Unknown) {
99
+ const position = sourceFile.getLineAndCharacterOfPosition(node.getStart());
100
+ diagnostics.push({
101
+ file: sourceFile.fileName,
102
+ line: position.line + 1, // 1-indexed
103
+ column: position.character + 1,
104
+ severity: STATIC_ANALYSIS.SEVERITY.ERROR,
105
+ rule: 'syntax-error',
106
+ message: 'Syntax error',
107
+ category: STATIC_ANALYSIS.CATEGORY.SYNTAX,
108
+ fixable: false
109
+ });
110
+ }
111
+
112
+ ts.forEachChild(node, visit);
113
+ };
114
+
115
+ visit(sourceFile);
116
+
117
+ // Also check for parsing errors
118
+ if (sourceFile.parseDiagnostics && sourceFile.parseDiagnostics.length > 0) {
119
+ for (const diagnostic of sourceFile.parseDiagnostics) {
120
+ diagnostics.push(this.formatDiagnostic(diagnostic, sourceFile));
121
+ }
122
+ }
123
+
124
+ return diagnostics;
125
+ }
126
+
127
+ /**
128
+ * Get semantic diagnostics (type errors, undefined variables)
129
+ * @private
130
+ */
131
+ async getSemanticDiagnostics(filePath, content) {
132
+ const diagnostics = [];
133
+
134
+ try {
135
+ // Create a minimal program for semantic analysis
136
+ const sourceFile = ts.createSourceFile(
137
+ filePath,
138
+ content,
139
+ ts.ScriptTarget.Latest,
140
+ true
141
+ );
142
+
143
+ // Create a compiler host that provides files from memory
144
+ const host = {
145
+ getSourceFile: (fileName) => {
146
+ if (fileName === filePath) {
147
+ return sourceFile;
148
+ }
149
+ return undefined;
150
+ },
151
+ getDefaultLibFileName: () => 'lib.d.ts',
152
+ writeFile: () => {},
153
+ getCurrentDirectory: () => path.dirname(filePath),
154
+ getDirectories: () => [],
155
+ fileExists: (fileName) => fileName === filePath,
156
+ readFile: (fileName) => {
157
+ if (fileName === filePath) {
158
+ return content;
159
+ }
160
+ return undefined;
161
+ },
162
+ getCanonicalFileName: (fileName) => fileName,
163
+ useCaseSensitiveFileNames: () => true,
164
+ getNewLine: () => '\n'
165
+ };
166
+
167
+ // Create program
168
+ const program = ts.createProgram({
169
+ rootNames: [filePath],
170
+ options: this.compilerOptions,
171
+ host
172
+ });
173
+
174
+ // Get semantic diagnostics
175
+ const tsDiagnostics = program.getSemanticDiagnostics(sourceFile);
176
+
177
+ for (const diagnostic of tsDiagnostics) {
178
+ diagnostics.push(this.formatDiagnostic(diagnostic, sourceFile));
179
+ }
180
+
181
+ } catch (error) {
182
+ this.logger?.debug('Semantic analysis skipped', {
183
+ file: filePath,
184
+ reason: error.message
185
+ });
186
+ }
187
+
188
+ return diagnostics;
189
+ }
190
+
191
+ /**
192
+ * Format TypeScript diagnostic to standard error format
193
+ * @private
194
+ */
195
+ formatDiagnostic(diagnostic, sourceFile) {
196
+ let line = 0;
197
+ let column = 0;
198
+
199
+ if (diagnostic.file && diagnostic.start !== undefined) {
200
+ const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
201
+ line = position.line + 1; // 1-indexed
202
+ column = position.character + 1;
203
+ } else if (sourceFile && diagnostic.start !== undefined) {
204
+ const position = sourceFile.getLineAndCharacterOfPosition(diagnostic.start);
205
+ line = position.line + 1;
206
+ column = position.character + 1;
207
+ }
208
+
209
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
210
+
211
+ // Determine severity
212
+ let severity;
213
+ switch (diagnostic.category) {
214
+ case ts.DiagnosticCategory.Error:
215
+ severity = STATIC_ANALYSIS.SEVERITY.ERROR;
216
+ break;
217
+ case ts.DiagnosticCategory.Warning:
218
+ severity = STATIC_ANALYSIS.SEVERITY.WARNING;
219
+ break;
220
+ case ts.DiagnosticCategory.Message:
221
+ case ts.DiagnosticCategory.Suggestion:
222
+ severity = STATIC_ANALYSIS.SEVERITY.INFO;
223
+ break;
224
+ default:
225
+ severity = STATIC_ANALYSIS.SEVERITY.ERROR;
226
+ }
227
+
228
+ // Determine category
229
+ let category = STATIC_ANALYSIS.CATEGORY.SYNTAX;
230
+ const code = diagnostic.code;
231
+
232
+ // Categorize based on error code
233
+ if (code >= 2000 && code < 3000) {
234
+ category = STATIC_ANALYSIS.CATEGORY.TYPE;
235
+ } else if (code >= 1000 && code < 2000) {
236
+ category = STATIC_ANALYSIS.CATEGORY.SYNTAX;
237
+ } else if (code >= 2300 && code < 2400) {
238
+ category = STATIC_ANALYSIS.CATEGORY.IMPORT;
239
+ }
240
+
241
+ // Check if message indicates import error
242
+ if (message.toLowerCase().includes('cannot find module') ||
243
+ message.toLowerCase().includes('import')) {
244
+ category = STATIC_ANALYSIS.CATEGORY.IMPORT;
245
+ }
246
+
247
+ return {
248
+ file: diagnostic.file?.fileName || sourceFile?.fileName || 'unknown',
249
+ line,
250
+ column,
251
+ severity,
252
+ rule: `TS${code}`,
253
+ message,
254
+ category,
255
+ fixable: false, // TypeScript doesn't provide fix information easily
256
+ code: diagnostic.code
257
+ };
258
+ }
259
+ }
260
+
261
+ export default JavaScriptAnalyzer;