auto-coder 0.1.327__py3-none-any.whl → 0.1.329__py3-none-any.whl

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.

Potentially problematic release.


This version of auto-coder might be problematic. Click here for more details.

@@ -0,0 +1,548 @@
1
+ """
2
+ Module for compiling/checking Vue.js code.
3
+ This module provides functionality to compile/check Vue.js code using tools like npm and vue-cli.
4
+ """
5
+
6
+ import os
7
+ import json
8
+ import subprocess
9
+ import tempfile
10
+ import time
11
+ import re
12
+ from typing import Dict, List, Any, Optional, Tuple
13
+
14
+ from autocoder.compilers.base_compiler import BaseCompiler
15
+ from autocoder.compilers.models import (
16
+ CompilationError,
17
+ FileCompilationResult,
18
+ ProjectCompilationResult,
19
+ CompilationErrorPosition,
20
+ CompilationErrorSeverity
21
+ )
22
+
23
+ class VueCompiler(BaseCompiler):
24
+ """
25
+ A class that provides compilation/checking functionality for Vue.js code.
26
+ """
27
+
28
+ def __init__(self, verbose: bool = False):
29
+ """
30
+ Initialize the VueCompiler.
31
+
32
+ Args:
33
+ verbose (bool): Whether to display verbose output.
34
+ """
35
+ super().__init__(verbose)
36
+
37
+ def get_supported_extensions(self) -> List[str]:
38
+ """
39
+ Get the list of file extensions supported by this compiler.
40
+
41
+ Returns:
42
+ List[str]: List of supported file extensions.
43
+ """
44
+ return ['.vue', '.js', '.ts']
45
+
46
+ def _check_dependencies(self) -> bool:
47
+ """
48
+ Check if required dependencies (node, npm) are installed.
49
+
50
+ Returns:
51
+ bool: True if all dependencies are available, False otherwise.
52
+ """
53
+ try:
54
+ # Check if node is installed
55
+ node_process = subprocess.run(
56
+ ['node', '--version'],
57
+ stdout=subprocess.PIPE,
58
+ stderr=subprocess.PIPE
59
+ )
60
+
61
+ # Check if npm is installed
62
+ npm_process = subprocess.run(
63
+ ['npm', '--version'],
64
+ stdout=subprocess.PIPE,
65
+ stderr=subprocess.PIPE
66
+ )
67
+
68
+ return node_process.returncode == 0 and npm_process.returncode == 0
69
+ except (subprocess.SubprocessError, FileNotFoundError):
70
+ return False
71
+
72
+ def _is_vue_project(self, project_path: str) -> bool:
73
+ """
74
+ Check if a directory is a Vue.js project.
75
+
76
+ Args:
77
+ project_path (str): Path to check.
78
+
79
+ Returns:
80
+ bool: True if the directory contains a Vue.js project, False otherwise.
81
+ """
82
+ # Check for package.json
83
+ package_json_path = os.path.join(project_path, 'package.json')
84
+ if not os.path.exists(package_json_path):
85
+ return False
86
+
87
+ try:
88
+ # Read package.json to check for Vue dependency
89
+ with open(package_json_path, 'r') as f:
90
+ package_data = json.load(f)
91
+
92
+ dependencies = package_data.get('dependencies', {})
93
+ dev_dependencies = package_data.get('devDependencies', {})
94
+
95
+ # Check if Vue is a dependency or vue-cli is a dev dependency
96
+ return ('vue' in dependencies or
97
+ 'vue' in dev_dependencies or
98
+ '@vue/cli-service' in dev_dependencies)
99
+ except:
100
+ return False
101
+
102
+ def _parse_error_position(self, error_text: str) -> Tuple[int, Optional[int]]:
103
+ """
104
+ Parse line and column from error text.
105
+
106
+ Args:
107
+ error_text (str): Error text to parse.
108
+
109
+ Returns:
110
+ Tuple[int, Optional[int]]: Line and column (if found).
111
+ """
112
+ # Look for common patterns like "Line X:Y" or "line X, column Y" or "LX:CY"
113
+ patterns = [
114
+ r'[Ll]ine\s+(\d+)(?:[,:]\s*(?:column\s+)?(\d+))?',
115
+ r'[Ll](\d+)(?:[,:]\s*[Cc](\d+))?',
116
+ r'[\(\[](\d+)[,:]\s*(\d+)[\)\]]',
117
+ r'at\s+\w+\s+\(.*?:(\d+)(?::(\d+))?\)'
118
+ ]
119
+
120
+ for pattern in patterns:
121
+ match = re.search(pattern, error_text)
122
+ if match:
123
+ line = int(match.group(1))
124
+ column = int(match.group(2)) if match.group(2) else None
125
+ return line, column
126
+
127
+ return 1, None # Default to line 1 if not found
128
+
129
+ def _parse_compilation_error(self, error_text: str, file_path: str) -> CompilationError:
130
+ """
131
+ Parse a compilation error message and create a CompilationError object.
132
+
133
+ Args:
134
+ error_text (str): Raw error message.
135
+ file_path (str): Path to the file with the error.
136
+
137
+ Returns:
138
+ CompilationError: Parsed error object.
139
+ """
140
+ line, column = self._parse_error_position(error_text)
141
+
142
+ return CompilationError(
143
+ message=error_text,
144
+ severity=CompilationErrorSeverity.ERROR,
145
+ position=CompilationErrorPosition(
146
+ line=line,
147
+ column=column
148
+ ),
149
+ file_path=file_path,
150
+ code="vue-compilation-error"
151
+ )
152
+
153
+ def _check_vue_file_syntax(self, file_path: str) -> Dict[str, Any]:
154
+ """
155
+ Check syntax of a Vue file using vue-template-compiler and babel.
156
+
157
+ Args:
158
+ file_path (str): Path to the file to check.
159
+
160
+ Returns:
161
+ Dict[str, Any]: Dictionary containing syntax check results.
162
+ """
163
+ errors = []
164
+ error_count = 0
165
+ warning_count = 0
166
+
167
+ try:
168
+ # Create a temporary directory
169
+ with tempfile.TemporaryDirectory() as temp_dir:
170
+ # Create a minimal package.json for Vue syntax checking
171
+ package_json = {
172
+ "name": "vue-syntax-checker",
173
+ "version": "1.0.0",
174
+ "description": "Temporary package for Vue syntax checking",
175
+ "dependencies": {
176
+ "vue": "^2.6.12",
177
+ "vue-template-compiler": "^2.6.12",
178
+ "@babel/core": "^7.14.0",
179
+ "@babel/preset-env": "^7.14.0"
180
+ },
181
+ "scripts": {
182
+ "check": "node check-vue.js"
183
+ }
184
+ }
185
+
186
+ # Write package.json
187
+ with open(os.path.join(temp_dir, 'package.json'), 'w') as f:
188
+ json.dump(package_json, f)
189
+
190
+ # Create a script to check Vue file syntax
191
+ checker_script = """
192
+ const fs = require('fs');
193
+ const compiler = require('vue-template-compiler');
194
+ const babel = require('@babel/core');
195
+
196
+ const filePath = process.argv[2];
197
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
198
+
199
+ try {
200
+ // Parse the Vue file
201
+ const parsed = compiler.parseComponent(fileContent);
202
+
203
+ // Check template syntax
204
+ if (parsed.template) {
205
+ try {
206
+ compiler.compile(parsed.template.content);
207
+ } catch (e) {
208
+ console.error(`Template error: ${e.message}`);
209
+ process.exit(1);
210
+ }
211
+ }
212
+
213
+ // Check script syntax
214
+ if (parsed.script) {
215
+ try {
216
+ babel.transformSync(parsed.script.content, {
217
+ presets: ['@babel/preset-env']
218
+ });
219
+ } catch (e) {
220
+ console.error(`Script error: ${e.message}`);
221
+ process.exit(1);
222
+ }
223
+ }
224
+
225
+ console.log('Syntax check passed');
226
+ process.exit(0);
227
+ } catch (e) {
228
+ console.error(`Error parsing Vue file: ${e.message}`);
229
+ process.exit(1);
230
+ }
231
+ """
232
+
233
+ # Write the checker script
234
+ with open(os.path.join(temp_dir, 'check-vue.js'), 'w') as f:
235
+ f.write(checker_script)
236
+
237
+ # Install dependencies
238
+ subprocess.run(
239
+ ['npm', 'install', '--silent'],
240
+ cwd=temp_dir,
241
+ stdout=subprocess.PIPE,
242
+ stderr=subprocess.PIPE
243
+ )
244
+
245
+ # Run the checker
246
+ cmd = ['node', 'check-vue.js', file_path]
247
+
248
+ process = subprocess.run(
249
+ cmd,
250
+ cwd=temp_dir,
251
+ stdout=subprocess.PIPE,
252
+ stderr=subprocess.PIPE,
253
+ text=True
254
+ )
255
+
256
+ # Check for syntax errors
257
+ if process.returncode != 0:
258
+ for line in process.stderr.splitlines():
259
+ if line.strip():
260
+ error = self._parse_compilation_error(line, file_path)
261
+ errors.append(error)
262
+ error_count += 1
263
+
264
+ except Exception as e:
265
+ errors.append(CompilationError(
266
+ message=f"Error checking syntax: {str(e)}",
267
+ severity=CompilationErrorSeverity.ERROR,
268
+ position=CompilationErrorPosition(line=1),
269
+ file_path=file_path,
270
+ code="syntax-check-error"
271
+ ))
272
+ error_count += 1
273
+
274
+ return {
275
+ 'success': error_count == 0,
276
+ 'errors': errors,
277
+ 'error_count': error_count,
278
+ 'warning_count': warning_count
279
+ }
280
+
281
+ def compile_file(self, file_path: str) -> Dict[str, Any]:
282
+ """
283
+ Compile (check) a single Vue.js file.
284
+
285
+ Args:
286
+ file_path (str): Path to the file to compile.
287
+
288
+ Returns:
289
+ Dict[str, Any]: Compilation results.
290
+ """
291
+ if not os.path.exists(file_path):
292
+ return FileCompilationResult(
293
+ file_path=file_path,
294
+ success=False,
295
+ language="vue",
296
+ error_message=f"File not found: {file_path}"
297
+ ).model_dump()
298
+
299
+ if not self.is_supported_file(file_path):
300
+ return FileCompilationResult(
301
+ file_path=file_path,
302
+ success=False,
303
+ language="vue",
304
+ error_message=f"Unsupported file type: {file_path}"
305
+ ).model_dump()
306
+
307
+ if not self._check_dependencies():
308
+ return FileCompilationResult(
309
+ file_path=file_path,
310
+ success=False,
311
+ language="vue",
312
+ error_message="Node.js and npm are required but not found. Please make sure they are installed."
313
+ ).model_dump()
314
+
315
+ start_time = time.time()
316
+
317
+ # Check syntax based on file type
318
+ if file_path.endswith('.vue'):
319
+ syntax_result = self._check_vue_file_syntax(file_path)
320
+ else:
321
+ # For .js and .ts files, reuse the same approach as ReactJS
322
+ from autocoder.compilers.reactjs_compiler import ReactJSCompiler
323
+ reactjs_compiler = ReactJSCompiler(verbose=self.verbose)
324
+ syntax_result = reactjs_compiler._check_file_syntax(file_path)
325
+
326
+ # Calculate execution time
327
+ execution_time_ms = int((time.time() - start_time) * 1000)
328
+
329
+ # Create the result
330
+ result = FileCompilationResult(
331
+ file_path=file_path,
332
+ success=syntax_result['success'],
333
+ language="vue",
334
+ errors=syntax_result['errors'],
335
+ error_count=syntax_result['error_count'],
336
+ warning_count=syntax_result['warning_count'],
337
+ info_count=0,
338
+ execution_time_ms=execution_time_ms
339
+ )
340
+
341
+ return result.model_dump()
342
+
343
+ def compile_project(self, project_path: str) -> Dict[str, Any]:
344
+ """
345
+ Compile (build) a Vue.js project.
346
+
347
+ Args:
348
+ project_path (str): Path to the project directory.
349
+
350
+ Returns:
351
+ Dict[str, Any]: Compilation results.
352
+ """
353
+ if not os.path.exists(project_path):
354
+ return ProjectCompilationResult(
355
+ project_path=project_path,
356
+ success=False,
357
+ total_files=0,
358
+ error_message=f"Project directory not found: {project_path}"
359
+ ).model_dump()
360
+
361
+ if not self._check_dependencies():
362
+ return ProjectCompilationResult(
363
+ project_path=project_path,
364
+ success=False,
365
+ total_files=0,
366
+ error_message="Node.js and npm are required but not found. Please make sure they are installed."
367
+ ).model_dump()
368
+
369
+ if not self._is_vue_project(project_path):
370
+ return ProjectCompilationResult(
371
+ project_path=project_path,
372
+ success=False,
373
+ total_files=0,
374
+ error_message=f"The directory does not appear to be a Vue.js project: {project_path}"
375
+ ).model_dump()
376
+
377
+ start_time = time.time()
378
+
379
+ # Run npm build
380
+ cmd = ['npm', 'run', 'build']
381
+
382
+ process = subprocess.run(
383
+ cmd,
384
+ cwd=project_path,
385
+ stdout=subprocess.PIPE,
386
+ stderr=subprocess.PIPE,
387
+ text=True
388
+ )
389
+
390
+ success = process.returncode == 0
391
+ output = process.stdout + process.stderr
392
+ errors = []
393
+ error_count = 0
394
+ warning_count = 0
395
+ file_results = {}
396
+ total_files = 0
397
+ files_with_errors = 0
398
+
399
+ # Find Vue files in the project
400
+ vue_files = []
401
+ for root, _, files in os.walk(project_path):
402
+ for file in files:
403
+ if any(file.endswith(ext) for ext in self.get_supported_extensions()):
404
+ # Skip node_modules directory
405
+ if 'node_modules' not in root:
406
+ file_path = os.path.join(root, file)
407
+ vue_files.append(file_path)
408
+ total_files += 1
409
+
410
+ if not success:
411
+ # Parse build errors
412
+ file_error_map = {} # Maps file paths to errors
413
+
414
+ # Look for error patterns in the output
415
+ # Vue CLI uses webpack, so errors are often similar to webpack errors
416
+ error_blocks = re.split(r'ERROR\s+in\s+|Module build failed|Failed to compile', output)
417
+
418
+ if len(error_blocks) > 1: # If we found error blocks
419
+ for block in error_blocks[1:]: # Skip the first block (before the error)
420
+ # Try to find file path in error block
421
+ file_match = re.search(r'((?:\.\./)*(?:src|components|views|pages).*?\.(?:vue|js|ts))', block)
422
+ if file_match:
423
+ error_file = os.path.join(project_path, file_match.group(1))
424
+ if os.path.exists(error_file):
425
+ error_message = block.strip()
426
+
427
+ if error_file not in file_error_map:
428
+ file_error_map[error_file] = []
429
+
430
+ error = self._parse_compilation_error(error_message, error_file)
431
+ file_error_map[error_file].append(error)
432
+ errors.append(error)
433
+ error_count += 1
434
+
435
+ # If no structured errors found, fall back to checking each file individually
436
+ if not errors:
437
+ for file_path in vue_files:
438
+ file_result = self.compile_file(file_path)
439
+ file_results[file_path] = file_result
440
+
441
+ if not file_result['success']:
442
+ files_with_errors += 1
443
+
444
+ error_count += file_result['error_count']
445
+ warning_count += file_result['warning_count']
446
+
447
+ # Add file errors to the project errors list
448
+ for error in file_result.get('errors', []):
449
+ errors.append(error)
450
+ else:
451
+ # Create file results from the error map
452
+ for file_path in vue_files:
453
+ file_errors = file_error_map.get(file_path, [])
454
+
455
+ file_result = FileCompilationResult(
456
+ file_path=file_path,
457
+ success=len(file_errors) == 0,
458
+ language="vue",
459
+ errors=file_errors,
460
+ error_count=len(file_errors),
461
+ warning_count=0,
462
+ info_count=0
463
+ )
464
+
465
+ file_results[file_path] = file_result.model_dump()
466
+
467
+ if len(file_errors) > 0:
468
+ files_with_errors += 1
469
+ else:
470
+ # If build succeeded, create a success result for each file
471
+ for file_path in vue_files:
472
+ file_result = FileCompilationResult(
473
+ file_path=file_path,
474
+ success=True,
475
+ language="vue",
476
+ errors=[],
477
+ error_count=0,
478
+ warning_count=0,
479
+ info_count=0
480
+ )
481
+
482
+ file_results[file_path] = file_result.model_dump()
483
+
484
+ # Calculate execution time
485
+ execution_time_ms = int((time.time() - start_time) * 1000)
486
+
487
+ # Determine output directory based on Vue.js versions
488
+ output_dir = os.path.join(project_path, 'dist')
489
+
490
+ # Create the project result
491
+ result = ProjectCompilationResult(
492
+ project_path=project_path,
493
+ success=success,
494
+ total_files=total_files,
495
+ files_with_errors=files_with_errors,
496
+ total_errors=error_count,
497
+ total_warnings=warning_count,
498
+ total_infos=0,
499
+ file_results={p: FileCompilationResult(**r) for p, r in file_results.items()},
500
+ output_directory=output_dir if success else None
501
+ )
502
+
503
+ return result.model_dump()
504
+
505
+ def format_compile_result(self, compile_result: Dict[str, Any]) -> str:
506
+ """
507
+ Format compilation results into a human-readable string.
508
+
509
+ Args:
510
+ compile_result (Dict[str, Any]): The compilation result dictionary.
511
+
512
+ Returns:
513
+ str: A formatted string representation of the compilation results.
514
+ """
515
+ if 'project_path' in compile_result:
516
+ # This is a project result
517
+ return ProjectCompilationResult(**compile_result).to_str()
518
+ else:
519
+ # This is a file result
520
+ return FileCompilationResult(**compile_result).to_str()
521
+
522
+ def compile_vue_file(file_path: str, verbose: bool = False) -> Dict[str, Any]:
523
+ """
524
+ Utility function to compile a single Vue.js file.
525
+
526
+ Args:
527
+ file_path (str): Path to the file to compile.
528
+ verbose (bool): Whether to display verbose output.
529
+
530
+ Returns:
531
+ Dict[str, Any]: A dictionary containing compilation results.
532
+ """
533
+ compiler = VueCompiler(verbose=verbose)
534
+ return compiler.compile_file(file_path)
535
+
536
+ def compile_vue_project(project_path: str, verbose: bool = False) -> Dict[str, Any]:
537
+ """
538
+ Utility function to compile a Vue.js project.
539
+
540
+ Args:
541
+ project_path (str): Path to the project directory.
542
+ verbose (bool): Whether to display verbose output.
543
+
544
+ Returns:
545
+ Dict[str, Any]: A dictionary containing compilation results.
546
+ """
547
+ compiler = VueCompiler(verbose=verbose)
548
+ return compiler.compile_project(project_path)
@@ -108,7 +108,7 @@ class ActiveContextManager:
108
108
  global_logger.configure(
109
109
  handlers=[
110
110
  # 移除控制台输出,只保留文件输出
111
- # 文件 Handler(仅处理 DirectoryMapper)
111
+ # 文件 Handler
112
112
  {
113
113
  "sink": log_file,
114
114
  "level": "INFO",
@@ -117,12 +117,12 @@ class ActiveContextManager:
117
117
  "format": "{time:YYYY-MM-DD HH:mm:ss} | {level} | {name} | {message}",
118
118
  "filter": lambda record: record["extra"].get("name") in ["DirectoryMapper", "ActiveContextManager","ActivePackage","AsyncProcessor"]
119
119
  },
120
- # 控制台 Handler(排除 DirectoryMapper)
120
+ # 控制台 Handler
121
121
  {
122
122
  "sink": sys.stdout,
123
123
  "level": "INFO",
124
124
  "format": "{time:YYYY-MM-DD HH:mm:ss} | {name} | {message}",
125
- "filter": lambda record: record["extra"].get("name") not in ["ActiveContextManager"]
125
+ "filter": lambda record: record["extra"].get("name") not in ["DirectoryMapper", "ActiveContextManager","ActivePackage","AsyncProcessor","TokenCostCalculator"]
126
126
  }
127
127
  ]
128
128
  )
@@ -192,7 +192,7 @@ class ActivePackage:
192
192
  end_time_current_change = time.monotonic()
193
193
 
194
194
  # 使用TokenCostCalculator跟踪token使用情况
195
- token_calculator = TokenCostCalculator(logger_name="ActivePackage.TokenCost",args=args)
195
+ token_calculator = TokenCostCalculator(logger_name="ActivePackage",args=args)
196
196
  current_change_stats: TokenUsageStats = token_calculator.track_token_usage(
197
197
  llm=self.llm,
198
198
  meta_holder=meta_holder_current_change,
@@ -316,7 +316,7 @@ class ActivePackage:
316
316
  end_time_current_change = time.monotonic()
317
317
 
318
318
  # 使用TokenCostCalculator跟踪token使用情况
319
- token_calculator = TokenCostCalculator(logger_name="ActivePackage.TokenCost",args=args)
319
+ token_calculator = TokenCostCalculator(logger_name="ActivePackage",args=args)
320
320
  update_current_change_stats: TokenUsageStats = token_calculator.track_token_usage(
321
321
  llm=self.llm,
322
322
  meta_holder=meta_holder_current_change,