auto-coder 0.1.326__py3-none-any.whl → 0.1.328__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,491 @@
1
+ """
2
+ Module for compiling/checking ReactJS code.
3
+ This module provides functionality to compile/check ReactJS code using tools like npm, babel, and webpack.
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 ReactJSCompiler(BaseCompiler):
24
+ """
25
+ A class that provides compilation/checking functionality for ReactJS code.
26
+ """
27
+
28
+ def __init__(self, verbose: bool = False):
29
+ """
30
+ Initialize the ReactJSCompiler.
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 ['.js', '.jsx', '.ts', '.tsx']
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_react_project(self, project_path: str) -> bool:
73
+ """
74
+ Check if a directory is a React project.
75
+
76
+ Args:
77
+ project_path (str): Path to check.
78
+
79
+ Returns:
80
+ bool: True if the directory contains a React 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 React 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 React is a dependency
96
+ return 'react' in dependencies or 'react' in dev_dependencies
97
+ except:
98
+ return False
99
+
100
+ def _parse_error_position(self, error_text: str) -> Tuple[int, Optional[int]]:
101
+ """
102
+ Parse line and column from error text.
103
+
104
+ Args:
105
+ error_text (str): Error text to parse.
106
+
107
+ Returns:
108
+ Tuple[int, Optional[int]]: Line and column (if found).
109
+ """
110
+ # Look for common patterns like "Line X:Y" or "line X, column Y" or "LX:CY"
111
+ patterns = [
112
+ r'[Ll]ine\s+(\d+)(?:[,:]\s*(?:column\s+)?(\d+))?',
113
+ r'[Ll](\d+)(?:[,:]\s*[Cc](\d+))?',
114
+ r'[\(\[](\d+)[,:]\s*(\d+)[\)\]]'
115
+ ]
116
+
117
+ for pattern in patterns:
118
+ match = re.search(pattern, error_text)
119
+ if match:
120
+ line = int(match.group(1))
121
+ column = int(match.group(2)) if match.group(2) else None
122
+ return line, column
123
+
124
+ return 1, None # Default to line 1 if not found
125
+
126
+ def _parse_compilation_error(self, error_text: str, file_path: str) -> CompilationError:
127
+ """
128
+ Parse a compilation error message and create a CompilationError object.
129
+
130
+ Args:
131
+ error_text (str): Raw error message.
132
+ file_path (str): Path to the file with the error.
133
+
134
+ Returns:
135
+ CompilationError: Parsed error object.
136
+ """
137
+ line, column = self._parse_error_position(error_text)
138
+
139
+ return CompilationError(
140
+ message=error_text,
141
+ severity=CompilationErrorSeverity.ERROR,
142
+ position=CompilationErrorPosition(
143
+ line=line,
144
+ column=column
145
+ ),
146
+ file_path=file_path,
147
+ code="react-compilation-error"
148
+ )
149
+
150
+ def _check_file_syntax(self, file_path: str) -> Dict[str, Any]:
151
+ """
152
+ Check syntax of a React/JavaScript file using Babel.
153
+
154
+ Args:
155
+ file_path (str): Path to the file to check.
156
+
157
+ Returns:
158
+ Dict[str, Any]: Dictionary containing syntax check results.
159
+ """
160
+ errors = []
161
+ error_count = 0
162
+ warning_count = 0
163
+
164
+ try:
165
+ # Create a temporary directory
166
+ with tempfile.TemporaryDirectory() as temp_dir:
167
+ # Create a minimal package.json
168
+ package_json = {
169
+ "name": "syntax-checker",
170
+ "version": "1.0.0",
171
+ "description": "Temporary package for syntax checking",
172
+ "dependencies": {
173
+ "@babel/core": "^7.14.0",
174
+ "@babel/preset-env": "^7.14.0",
175
+ "@babel/preset-react": "^7.13.13"
176
+ },
177
+ "scripts": {
178
+ "check": "babel --presets=@babel/preset-env,@babel/preset-react --no-babelrc --filename \"$FILE\" --check-syntax-only"
179
+ }
180
+ }
181
+
182
+ # If the file is TypeScript, add TypeScript dependencies
183
+ if file_path.endswith('.ts') or file_path.endswith('.tsx'):
184
+ package_json["dependencies"]["@babel/preset-typescript"] = "^7.13.0"
185
+ package_json["scripts"]["check"] = "babel --presets=@babel/preset-env,@babel/preset-react,@babel/preset-typescript --no-babelrc --filename \"$FILE\" --check-syntax-only"
186
+
187
+ # Write package.json
188
+ with open(os.path.join(temp_dir, 'package.json'), 'w') as f:
189
+ json.dump(package_json, f)
190
+
191
+ # Install dependencies
192
+ subprocess.run(
193
+ ['npm', 'install', '--silent'],
194
+ cwd=temp_dir,
195
+ stdout=subprocess.PIPE,
196
+ stderr=subprocess.PIPE
197
+ )
198
+
199
+ # Run babel to check syntax
200
+ cmd = f'FILE={file_path} npm run check -- {file_path}'
201
+
202
+ process = subprocess.run(
203
+ cmd,
204
+ shell=True,
205
+ cwd=temp_dir,
206
+ stdout=subprocess.PIPE,
207
+ stderr=subprocess.PIPE,
208
+ text=True
209
+ )
210
+
211
+ # Check for syntax errors
212
+ if process.returncode != 0:
213
+ for line in process.stderr.splitlines():
214
+ if line and not line.startswith('npm'):
215
+ error = self._parse_compilation_error(line, file_path)
216
+ errors.append(error)
217
+ error_count += 1
218
+
219
+ except Exception as e:
220
+ errors.append(CompilationError(
221
+ message=f"Error checking syntax: {str(e)}",
222
+ severity=CompilationErrorSeverity.ERROR,
223
+ position=CompilationErrorPosition(line=1),
224
+ file_path=file_path,
225
+ code="syntax-check-error"
226
+ ))
227
+ error_count += 1
228
+
229
+ return {
230
+ 'success': error_count == 0,
231
+ 'errors': errors,
232
+ 'error_count': error_count,
233
+ 'warning_count': warning_count
234
+ }
235
+
236
+ def compile_file(self, file_path: str) -> Dict[str, Any]:
237
+ """
238
+ Compile (check) a single ReactJS file.
239
+
240
+ Args:
241
+ file_path (str): Path to the file to compile.
242
+
243
+ Returns:
244
+ Dict[str, Any]: Compilation results.
245
+ """
246
+ if not os.path.exists(file_path):
247
+ return FileCompilationResult(
248
+ file_path=file_path,
249
+ success=False,
250
+ language="react",
251
+ error_message=f"File not found: {file_path}"
252
+ ).model_dump()
253
+
254
+ if not self.is_supported_file(file_path):
255
+ return FileCompilationResult(
256
+ file_path=file_path,
257
+ success=False,
258
+ language="react",
259
+ error_message=f"Unsupported file type: {file_path}"
260
+ ).model_dump()
261
+
262
+ if not self._check_dependencies():
263
+ return FileCompilationResult(
264
+ file_path=file_path,
265
+ success=False,
266
+ language="react",
267
+ error_message="Node.js and npm are required but not found. Please make sure they are installed."
268
+ ).model_dump()
269
+
270
+ start_time = time.time()
271
+
272
+ # Check syntax
273
+ syntax_result = self._check_file_syntax(file_path)
274
+
275
+ # Calculate execution time
276
+ execution_time_ms = int((time.time() - start_time) * 1000)
277
+
278
+ # Create the result
279
+ result = FileCompilationResult(
280
+ file_path=file_path,
281
+ success=syntax_result['success'],
282
+ language="react",
283
+ errors=syntax_result['errors'],
284
+ error_count=syntax_result['error_count'],
285
+ warning_count=syntax_result['warning_count'],
286
+ info_count=0,
287
+ execution_time_ms=execution_time_ms
288
+ )
289
+
290
+ return result.model_dump()
291
+
292
+ def compile_project(self, project_path: str) -> Dict[str, Any]:
293
+ """
294
+ Compile (build) a ReactJS project.
295
+
296
+ Args:
297
+ project_path (str): Path to the project directory.
298
+
299
+ Returns:
300
+ Dict[str, Any]: Compilation results.
301
+ """
302
+ if not os.path.exists(project_path):
303
+ return ProjectCompilationResult(
304
+ project_path=project_path,
305
+ success=False,
306
+ total_files=0,
307
+ error_message=f"Project directory not found: {project_path}"
308
+ ).model_dump()
309
+
310
+ if not self._check_dependencies():
311
+ return ProjectCompilationResult(
312
+ project_path=project_path,
313
+ success=False,
314
+ total_files=0,
315
+ error_message="Node.js and npm are required but not found. Please make sure they are installed."
316
+ ).model_dump()
317
+
318
+ if not self._is_react_project(project_path):
319
+ return ProjectCompilationResult(
320
+ project_path=project_path,
321
+ success=False,
322
+ total_files=0,
323
+ error_message=f"The directory does not appear to be a React project: {project_path}"
324
+ ).model_dump()
325
+
326
+ start_time = time.time()
327
+
328
+ # Run npm build
329
+ cmd = ['npm', 'run', 'build']
330
+
331
+ process = subprocess.run(
332
+ cmd,
333
+ cwd=project_path,
334
+ stdout=subprocess.PIPE,
335
+ stderr=subprocess.PIPE,
336
+ text=True
337
+ )
338
+
339
+ success = process.returncode == 0
340
+ output = process.stdout + process.stderr
341
+ errors = []
342
+ error_count = 0
343
+ warning_count = 0
344
+ file_results = {}
345
+ total_files = 0
346
+ files_with_errors = 0
347
+
348
+ # Find React files in the project
349
+ react_files = []
350
+ for root, _, files in os.walk(project_path):
351
+ for file in files:
352
+ if any(file.endswith(ext) for ext in self.get_supported_extensions()):
353
+ file_path = os.path.join(root, file)
354
+ react_files.append(file_path)
355
+ total_files += 1
356
+
357
+ if not success:
358
+ # Parse build errors
359
+ file_error_map = {} # Maps file paths to errors
360
+
361
+ # Look for webpack error patterns
362
+ error_blocks = re.split(r'Module build failed|Failed to compile', output)
363
+
364
+ if len(error_blocks) > 1: # If we found error blocks
365
+ for block in error_blocks[1:]: # Skip the first block (before the error)
366
+ # Try to find file path
367
+ file_match = re.search(r'((?:\.\./)*(?:src|components|pages|views).*?\.(?:js|jsx|ts|tsx))', block)
368
+ if file_match:
369
+ error_file = os.path.join(project_path, file_match.group(1))
370
+ if os.path.exists(error_file):
371
+ error_message = block.strip()
372
+
373
+ if error_file not in file_error_map:
374
+ file_error_map[error_file] = []
375
+
376
+ error = self._parse_compilation_error(error_message, error_file)
377
+ file_error_map[error_file].append(error)
378
+ errors.append(error)
379
+ error_count += 1
380
+
381
+ # If no structured errors found, fall back to checking each file individually
382
+ if len(errors) == 0:
383
+ for file_path in react_files:
384
+ file_result = self.compile_file(file_path)
385
+ file_results[file_path] = file_result
386
+
387
+ if not file_result['success']:
388
+ files_with_errors += 1
389
+
390
+ error_count += file_result['error_count']
391
+ warning_count += file_result['warning_count']
392
+
393
+ # Add file errors to the project errors list
394
+ for error in file_result.get('errors', []):
395
+ errors.append(error)
396
+ else:
397
+ # Create file results from the error map
398
+ for file_path in react_files:
399
+ file_errors = file_error_map.get(file_path, [])
400
+
401
+ file_result = FileCompilationResult(
402
+ file_path=file_path,
403
+ success=len(file_errors) == 0,
404
+ language="react",
405
+ errors=file_errors,
406
+ error_count=len(file_errors),
407
+ warning_count=0,
408
+ info_count=0
409
+ )
410
+
411
+ file_results[file_path] = file_result.model_dump()
412
+
413
+ if len(file_errors) > 0:
414
+ files_with_errors += 1
415
+ else:
416
+ # If build succeeded, create a success result for each file
417
+ for file_path in react_files:
418
+ file_result = FileCompilationResult(
419
+ file_path=file_path,
420
+ success=True,
421
+ language="react",
422
+ errors=[],
423
+ error_count=0,
424
+ warning_count=0,
425
+ info_count=0
426
+ )
427
+
428
+ file_results[file_path] = file_result.model_dump()
429
+
430
+ # Calculate execution time
431
+ execution_time_ms = int((time.time() - start_time) * 1000)
432
+
433
+ # Create the project result
434
+ result = ProjectCompilationResult(
435
+ project_path=project_path,
436
+ success=success,
437
+ total_files=total_files,
438
+ files_with_errors=files_with_errors,
439
+ total_errors=error_count,
440
+ total_warnings=warning_count,
441
+ total_infos=0,
442
+ file_results={p: FileCompilationResult(**r) for p, r in file_results.items()},
443
+ output_directory=os.path.join(project_path, 'build') if success else None
444
+ )
445
+
446
+ return result.model_dump()
447
+
448
+ def format_compile_result(self, compile_result: Dict[str, Any]) -> str:
449
+ """
450
+ Format compilation results into a human-readable string.
451
+
452
+ Args:
453
+ compile_result (Dict[str, Any]): The compilation result dictionary.
454
+
455
+ Returns:
456
+ str: A formatted string representation of the compilation results.
457
+ """
458
+ if 'project_path' in compile_result:
459
+ # This is a project result
460
+ return ProjectCompilationResult(**compile_result).to_str()
461
+ else:
462
+ # This is a file result
463
+ return FileCompilationResult(**compile_result).to_str()
464
+
465
+ def compile_reactjs_file(file_path: str, verbose: bool = False) -> Dict[str, Any]:
466
+ """
467
+ Utility function to compile a single ReactJS file.
468
+
469
+ Args:
470
+ file_path (str): Path to the file to compile.
471
+ verbose (bool): Whether to display verbose output.
472
+
473
+ Returns:
474
+ Dict[str, Any]: A dictionary containing compilation results.
475
+ """
476
+ compiler = ReactJSCompiler(verbose=verbose)
477
+ return compiler.compile_file(file_path)
478
+
479
+ def compile_reactjs_project(project_path: str, verbose: bool = False) -> Dict[str, Any]:
480
+ """
481
+ Utility function to compile a ReactJS project.
482
+
483
+ Args:
484
+ project_path (str): Path to the project directory.
485
+ verbose (bool): Whether to display verbose output.
486
+
487
+ Returns:
488
+ Dict[str, Any]: A dictionary containing compilation results.
489
+ """
490
+ compiler = ReactJSCompiler(verbose=verbose)
491
+ return compiler.compile_project(project_path)
@@ -0,0 +1,42 @@
1
+ import os
2
+ from typing import Optional
3
+ from autocoder.shadows.shadow_manager import ShadowManager
4
+ from autocoder.compilers.compiler_factory import CompilerFactory
5
+ from autocoder.compilers.models import ProjectCompilationResult,FileCompilationResult
6
+
7
+ class ShadowCompiler:
8
+ """
9
+ 用于对ShadowManager管理的文件进行代码检查并将结果转换回项目路径的类。
10
+ """
11
+
12
+ def __init__(self, shadow_manager: ShadowManager,verbose:bool=False):
13
+ """
14
+ 使用ShadowManager实例初始化。
15
+
16
+ 参数:
17
+ shadow_manager (ShadowManager): 用于管理文件路径映射的实例
18
+ verbose (bool): 是否启用详细输出
19
+ """
20
+ self.shadow_manager = shadow_manager
21
+ self.compiler = CompilerFactory.create_compiler(language="provided",config_path=os.path.join(self.shadow_manager.source_dir,".auto-coder","projects","compiler.yml"))
22
+
23
+ def compile_shadow_file(self, shadow_path: str) -> FileCompilationResult:
24
+ return FileCompilationResult(
25
+ file_path=shadow_path,
26
+ success=True,
27
+ language="provided",
28
+ errors=[],
29
+ error_message=None,
30
+ warning_count=0,
31
+ error_count=0,
32
+ info_count=0,
33
+ execution_time_ms=0,
34
+ output_file=None
35
+ )
36
+
37
+ def compile_all_shadow_files(self,target_compiler_name:Optional[str]=None) -> ProjectCompilationResult:
38
+ link_projects_dir = self.shadow_manager.create_link_project()
39
+ result = self.compiler.compile_project(link_projects_dir,target_compiler_name)
40
+ result.project_path = self.shadow_manager.source_dir
41
+ return result
42
+