@friggframework/devtools 2.0.0--canary.398.7664c46.0 → 2.0.0--canary.400.bed3308.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/frigg-cli/.eslintrc.js +141 -0
- package/frigg-cli/__tests__/jest.config.js +102 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
- package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
- package/frigg-cli/__tests__/utils/command-tester.js +170 -0
- package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
- package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
- package/frigg-cli/__tests__/utils/test-setup.js +286 -0
- package/frigg-cli/build-command/index.js +15 -2
- package/frigg-cli/deploy-command/index.js +15 -2
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
- package/frigg-cli/generate-command/azure-generator.js +43 -0
- package/frigg-cli/generate-command/gcp-generator.js +47 -0
- package/frigg-cli/generate-command/index.js +350 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/index.js +66 -4
- package/frigg-cli/install-command/index.js +15 -2
- package/frigg-cli/package.json +75 -0
- package/frigg-cli/start-command/index.js +17 -2
- package/frigg-cli/ui-command/index.js +167 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +38 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +43 -19
- package/infrastructure/IAM-POLICY-TEMPLATES.md +1 -1
- package/infrastructure/frigg-deployment-iam-stack.yaml +16 -2
- package/infrastructure/iam-generator.js +129 -6
- package/infrastructure/iam-policy-basic.json +29 -5
- package/infrastructure/iam-policy-full.json +28 -5
- package/infrastructure/serverless-template.js +209 -3
- package/infrastructure/serverless-template.test.js +12 -0
- package/management-ui/.eslintrc.js +22 -0
- package/management-ui/README.md +203 -0
- package/management-ui/components.json +21 -0
- package/management-ui/{dist/index.html → index.html} +1 -2
- package/management-ui/merge-conflict-cleaner.py +371 -0
- package/management-ui/package-lock.json +10997 -0
- package/management-ui/package.json +76 -0
- package/management-ui/postcss.config.js +6 -0
- package/management-ui/server/api/backend.js +256 -0
- package/management-ui/server/api/cli.js +315 -0
- package/management-ui/server/api/codegen.js +663 -0
- package/management-ui/server/api/connections.js +857 -0
- package/management-ui/server/api/discovery.js +185 -0
- package/management-ui/server/api/environment/index.js +1 -0
- package/management-ui/server/api/environment/router.js +378 -0
- package/management-ui/server/api/environment.js +328 -0
- package/management-ui/server/api/integrations.js +479 -0
- package/management-ui/server/api/logs.js +248 -0
- package/management-ui/server/api/monitoring.js +282 -0
- package/management-ui/server/api/open-ide.js +31 -0
- package/management-ui/server/api/project.js +553 -0
- package/management-ui/server/api/users/sessions.js +371 -0
- package/management-ui/server/api/users/simulation.js +254 -0
- package/management-ui/server/api/users.js +362 -0
- package/management-ui/server/api-contract.md +275 -0
- package/management-ui/server/index.js +428 -0
- package/management-ui/server/middleware/errorHandler.js +70 -0
- package/management-ui/server/middleware/security.js +32 -0
- package/management-ui/server/processManager.js +296 -0
- package/management-ui/server/server.js +188 -0
- package/management-ui/server/services/aws-monitor.js +413 -0
- package/management-ui/server/services/npm-registry.js +347 -0
- package/management-ui/server/services/template-engine.js +538 -0
- package/management-ui/server/utils/cliIntegration.js +220 -0
- package/management-ui/server/utils/environment/auditLogger.js +471 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
- package/management-ui/server/utils/environment/encryption.js +278 -0
- package/management-ui/server/utils/environment/envFileManager.js +286 -0
- package/management-ui/server/utils/import-commonjs.js +28 -0
- package/management-ui/server/utils/response.js +83 -0
- package/management-ui/server/websocket/handler.js +325 -0
- package/management-ui/src/App.jsx +51 -0
- package/management-ui/src/components/AppRouter.jsx +65 -0
- package/management-ui/src/components/Button.jsx +2 -0
- package/management-ui/src/components/Card.jsx +9 -0
- package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
- package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
- package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
- package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
- package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
- package/management-ui/src/components/ErrorBoundary.jsx +73 -0
- package/management-ui/src/components/IntegrationCard.jsx +199 -0
- package/management-ui/src/components/IntegrationCardEnhanced.jsx +490 -0
- package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
- package/management-ui/src/components/IntegrationStatus.jsx +235 -0
- package/management-ui/src/components/Layout.jsx +250 -0
- package/management-ui/src/components/LoadingSpinner.jsx +45 -0
- package/management-ui/src/components/RepositoryPicker.jsx +248 -0
- package/management-ui/src/components/SessionMonitor.jsx +255 -0
- package/management-ui/src/components/StatusBadge.jsx +70 -0
- package/management-ui/src/components/UserContextSwitcher.jsx +154 -0
- package/management-ui/src/components/UserSimulation.jsx +299 -0
- package/management-ui/src/components/Welcome.jsx +434 -0
- package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
- package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
- package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
- package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
- package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
- package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
- package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
- package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
- package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
- package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
- package/management-ui/src/components/codegen/index.js +10 -0
- package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
- package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
- package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
- package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
- package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
- package/management-ui/src/components/connections/index.js +5 -0
- package/management-ui/src/components/index.js +21 -0
- package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
- package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
- package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
- package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
- package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
- package/management-ui/src/components/monitoring/index.js +6 -0
- package/management-ui/src/components/monitoring/monitoring.css +218 -0
- package/management-ui/src/components/theme-provider.jsx +52 -0
- package/management-ui/src/components/theme-toggle.jsx +39 -0
- package/management-ui/src/components/ui/badge.tsx +36 -0
- package/management-ui/src/components/ui/button.test.jsx +56 -0
- package/management-ui/src/components/ui/button.tsx +57 -0
- package/management-ui/src/components/ui/card.tsx +76 -0
- package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
- package/management-ui/src/components/ui/select.tsx +157 -0
- package/management-ui/src/components/ui/skeleton.jsx +15 -0
- package/management-ui/src/hooks/useFrigg.jsx +387 -0
- package/management-ui/src/hooks/useSocket.jsx +58 -0
- package/management-ui/src/index.css +194 -0
- package/management-ui/src/lib/utils.ts +6 -0
- package/management-ui/src/main.jsx +10 -0
- package/management-ui/src/pages/CodeGeneration.jsx +14 -0
- package/management-ui/src/pages/Connections.jsx +252 -0
- package/management-ui/src/pages/ConnectionsEnhanced.jsx +427 -0
- package/management-ui/src/pages/Dashboard.jsx +311 -0
- package/management-ui/src/pages/Environment.jsx +314 -0
- package/management-ui/src/pages/IntegrationConfigure.jsx +544 -0
- package/management-ui/src/pages/IntegrationDiscovery.jsx +479 -0
- package/management-ui/src/pages/IntegrationTest.jsx +494 -0
- package/management-ui/src/pages/Integrations.jsx +254 -0
- package/management-ui/src/pages/Monitoring.jsx +17 -0
- package/management-ui/src/pages/Simulation.jsx +155 -0
- package/management-ui/src/pages/Users.jsx +492 -0
- package/management-ui/src/services/api.js +41 -0
- package/management-ui/src/services/apiModuleService.js +193 -0
- package/management-ui/src/services/websocket-handlers.js +120 -0
- package/management-ui/src/test/api/project.test.js +273 -0
- package/management-ui/src/test/components/Welcome.test.jsx +378 -0
- package/management-ui/src/test/mocks/server.js +178 -0
- package/management-ui/src/test/setup.js +61 -0
- package/management-ui/src/test/utils/test-utils.jsx +134 -0
- package/management-ui/src/utils/repository.js +98 -0
- package/management-ui/src/utils/repository.test.js +118 -0
- package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
- package/management-ui/tailwind.config.js +63 -0
- package/management-ui/tsconfig.json +37 -0
- package/management-ui/tsconfig.node.json +10 -0
- package/management-ui/vite.config.js +26 -0
- package/management-ui/vitest.config.js +38 -0
- package/package.json +5 -5
- package/management-ui/dist/assets/index-CbM64Oba.js +0 -1221
- package/management-ui/dist/assets/index-CkvseXTC.css +0 -1
- /package/management-ui/{dist/assets/FriggLogo-B7Xx8ZW1.svg → src/assets/FriggLogo.svg} +0 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Merge Conflict Cleaner Script
|
|
4
|
+
|
|
5
|
+
This script automatically cleans up merge conflicts by:
|
|
6
|
+
1. Removing duplicate imports
|
|
7
|
+
2. Keeping the most complete version of duplicated code blocks
|
|
8
|
+
3. Ensuring proper syntax after cleanup
|
|
9
|
+
4. Preserving functionality while removing conflicts
|
|
10
|
+
|
|
11
|
+
Focus on these key patterns:
|
|
12
|
+
- Import dedupe and consolidation
|
|
13
|
+
- Taking the most complete version of components
|
|
14
|
+
- Preserving industrial design system elements
|
|
15
|
+
- Keeping proper React patterns
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import re
|
|
20
|
+
import sys
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import List, Dict, Set, Tuple
|
|
23
|
+
import logging
|
|
24
|
+
|
|
25
|
+
# Configure logging
|
|
26
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
class MergeConflictCleaner:
|
|
30
|
+
def __init__(self, base_path: str):
|
|
31
|
+
self.base_path = Path(base_path)
|
|
32
|
+
self.files_processed = 0
|
|
33
|
+
self.conflicts_resolved = 0
|
|
34
|
+
self.errors = []
|
|
35
|
+
|
|
36
|
+
def find_conflict_files(self) -> List[Path]:
|
|
37
|
+
"""Find all files with merge conflict markers"""
|
|
38
|
+
conflict_files = []
|
|
39
|
+
|
|
40
|
+
for file_path in self.base_path.rglob('*.jsx'):
|
|
41
|
+
if self._has_conflicts(file_path):
|
|
42
|
+
conflict_files.append(file_path)
|
|
43
|
+
|
|
44
|
+
for file_path in self.base_path.rglob('*.js'):
|
|
45
|
+
if self._has_conflicts(file_path):
|
|
46
|
+
conflict_files.append(file_path)
|
|
47
|
+
|
|
48
|
+
for file_path in self.base_path.rglob('*.css'):
|
|
49
|
+
if self._has_conflicts(file_path):
|
|
50
|
+
conflict_files.append(file_path)
|
|
51
|
+
|
|
52
|
+
return conflict_files
|
|
53
|
+
|
|
54
|
+
def _has_conflicts(self, file_path: Path) -> bool:
|
|
55
|
+
"""Check if file has merge conflict markers"""
|
|
56
|
+
try:
|
|
57
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
58
|
+
content = f.read()
|
|
59
|
+
return any(marker in content for marker in ['<<<<<<<', '=======', '>>>>>>>'])
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.error(f"Error reading {file_path}: {e}")
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
def clean_file(self, file_path: Path) -> bool:
|
|
65
|
+
"""Clean merge conflicts in a single file"""
|
|
66
|
+
try:
|
|
67
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
68
|
+
content = f.read()
|
|
69
|
+
|
|
70
|
+
logger.info(f"Processing {file_path}")
|
|
71
|
+
|
|
72
|
+
# Parse and resolve conflicts
|
|
73
|
+
cleaned_content = self._resolve_conflicts(content, file_path)
|
|
74
|
+
|
|
75
|
+
# Write cleaned content back
|
|
76
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
77
|
+
f.write(cleaned_content)
|
|
78
|
+
|
|
79
|
+
self.files_processed += 1
|
|
80
|
+
return True
|
|
81
|
+
|
|
82
|
+
except Exception as e:
|
|
83
|
+
error_msg = f"Error processing {file_path}: {e}"
|
|
84
|
+
logger.error(error_msg)
|
|
85
|
+
self.errors.append(error_msg)
|
|
86
|
+
return False
|
|
87
|
+
|
|
88
|
+
def _resolve_conflicts(self, content: str, file_path: Path) -> str:
|
|
89
|
+
"""Resolve merge conflicts in content"""
|
|
90
|
+
lines = content.split('\n')
|
|
91
|
+
cleaned_lines = []
|
|
92
|
+
i = 0
|
|
93
|
+
|
|
94
|
+
while i < len(lines):
|
|
95
|
+
line = lines[i]
|
|
96
|
+
|
|
97
|
+
# Check for conflict start
|
|
98
|
+
if line.startswith('<<<<<<<'):
|
|
99
|
+
conflict_resolved = self._resolve_conflict_block(lines, i, file_path)
|
|
100
|
+
if conflict_resolved:
|
|
101
|
+
resolved_lines, skip_count = conflict_resolved
|
|
102
|
+
cleaned_lines.extend(resolved_lines)
|
|
103
|
+
i += skip_count
|
|
104
|
+
self.conflicts_resolved += 1
|
|
105
|
+
else:
|
|
106
|
+
# If we can't resolve, keep the line as is
|
|
107
|
+
cleaned_lines.append(line)
|
|
108
|
+
i += 1
|
|
109
|
+
else:
|
|
110
|
+
cleaned_lines.append(line)
|
|
111
|
+
i += 1
|
|
112
|
+
|
|
113
|
+
return '\n'.join(cleaned_lines)
|
|
114
|
+
|
|
115
|
+
def _resolve_conflict_block(self, lines: List[str], start_idx: int, file_path: Path) -> Tuple[List[str], int]:
|
|
116
|
+
"""Resolve a single conflict block"""
|
|
117
|
+
# Find the boundaries of the conflict
|
|
118
|
+
head_start = start_idx
|
|
119
|
+
separator_idx = -1
|
|
120
|
+
end_idx = -1
|
|
121
|
+
|
|
122
|
+
for i in range(start_idx + 1, len(lines)):
|
|
123
|
+
if lines[i].startswith('======='):
|
|
124
|
+
separator_idx = i
|
|
125
|
+
elif lines[i].startswith('>>>>>>>'):
|
|
126
|
+
end_idx = i
|
|
127
|
+
break
|
|
128
|
+
|
|
129
|
+
if separator_idx == -1 or end_idx == -1:
|
|
130
|
+
logger.warning(f"Malformed conflict block at line {start_idx + 1} in {file_path}")
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
# Extract the two versions
|
|
134
|
+
head_version = lines[head_start + 1:separator_idx]
|
|
135
|
+
incoming_version = lines[separator_idx + 1:end_idx]
|
|
136
|
+
|
|
137
|
+
# Resolve based on file-specific logic
|
|
138
|
+
resolved_lines = self._choose_best_version(head_version, incoming_version, file_path)
|
|
139
|
+
|
|
140
|
+
# Return resolved lines and number of lines to skip
|
|
141
|
+
return resolved_lines, end_idx - start_idx + 1
|
|
142
|
+
|
|
143
|
+
def _choose_best_version(self, head_version: List[str], incoming_version: List[str], file_path: Path) -> List[str]:
|
|
144
|
+
"""Choose the best version based on content analysis"""
|
|
145
|
+
|
|
146
|
+
# Handle imports specially
|
|
147
|
+
if self._is_import_block(head_version) or self._is_import_block(incoming_version):
|
|
148
|
+
return self._merge_imports(head_version, incoming_version)
|
|
149
|
+
|
|
150
|
+
# Handle export statements
|
|
151
|
+
if self._is_export_block(head_version) or self._is_export_block(incoming_version):
|
|
152
|
+
return self._merge_exports(head_version, incoming_version)
|
|
153
|
+
|
|
154
|
+
# For Layout.jsx and similar component files, prefer the more complete version
|
|
155
|
+
if 'Layout.jsx' in str(file_path):
|
|
156
|
+
return self._resolve_layout_conflicts(head_version, incoming_version)
|
|
157
|
+
|
|
158
|
+
# For Button.jsx, prefer the shadcn re-export version
|
|
159
|
+
if 'Button.jsx' in str(file_path):
|
|
160
|
+
return self._resolve_button_conflicts(head_version, incoming_version)
|
|
161
|
+
|
|
162
|
+
# General heuristic: prefer the version with more content
|
|
163
|
+
if len(''.join(head_version).strip()) > len(''.join(incoming_version).strip()):
|
|
164
|
+
return head_version
|
|
165
|
+
else:
|
|
166
|
+
return incoming_version
|
|
167
|
+
|
|
168
|
+
def _is_import_block(self, lines: List[str]) -> bool:
|
|
169
|
+
"""Check if this is an import block"""
|
|
170
|
+
content = ''.join(lines).strip()
|
|
171
|
+
return content.startswith('import') or 'import' in content
|
|
172
|
+
|
|
173
|
+
def _is_export_block(self, lines: List[str]) -> bool:
|
|
174
|
+
"""Check if this is an export block"""
|
|
175
|
+
content = ''.join(lines).strip()
|
|
176
|
+
return content.startswith('export') or 'export' in content
|
|
177
|
+
|
|
178
|
+
def _merge_imports(self, head_version: List[str], incoming_version: List[str]) -> List[str]:
|
|
179
|
+
"""Merge and deduplicate imports"""
|
|
180
|
+
all_imports = set()
|
|
181
|
+
import_lines = []
|
|
182
|
+
|
|
183
|
+
# Process both versions
|
|
184
|
+
for version in [head_version, incoming_version]:
|
|
185
|
+
for line in version:
|
|
186
|
+
line = line.strip()
|
|
187
|
+
if line and not line.startswith('//'):
|
|
188
|
+
# Extract import statements
|
|
189
|
+
if line.startswith('import'):
|
|
190
|
+
if line not in all_imports:
|
|
191
|
+
all_imports.add(line)
|
|
192
|
+
import_lines.append(line)
|
|
193
|
+
elif 'import' in line and '{' in line:
|
|
194
|
+
# Handle multi-line imports
|
|
195
|
+
if line not in all_imports:
|
|
196
|
+
all_imports.add(line)
|
|
197
|
+
import_lines.append(line)
|
|
198
|
+
|
|
199
|
+
# Sort imports for consistency
|
|
200
|
+
import_lines.sort()
|
|
201
|
+
return import_lines
|
|
202
|
+
|
|
203
|
+
def _merge_exports(self, head_version: List[str], incoming_version: List[str]) -> List[str]:
|
|
204
|
+
"""Merge exports, preferring named exports"""
|
|
205
|
+
for version in [head_version, incoming_version]:
|
|
206
|
+
for line in version:
|
|
207
|
+
if 'export {' in line:
|
|
208
|
+
return version
|
|
209
|
+
|
|
210
|
+
# If no named exports, prefer the version with more content
|
|
211
|
+
if len(''.join(head_version).strip()) > len(''.join(incoming_version).strip()):
|
|
212
|
+
return head_version
|
|
213
|
+
else:
|
|
214
|
+
return incoming_version
|
|
215
|
+
|
|
216
|
+
def _resolve_layout_conflicts(self, head_version: List[str], incoming_version: List[str]) -> List[str]:
|
|
217
|
+
"""Resolve Layout.jsx specific conflicts"""
|
|
218
|
+
# Look for industrial design elements
|
|
219
|
+
head_content = ''.join(head_version)
|
|
220
|
+
incoming_content = ''.join(incoming_version)
|
|
221
|
+
|
|
222
|
+
# Prefer version with industrial design elements
|
|
223
|
+
industrial_keywords = ['industrial', 'FriggLogo', 'ThemeToggle', 'RepositoryPicker']
|
|
224
|
+
|
|
225
|
+
head_score = sum(1 for keyword in industrial_keywords if keyword in head_content)
|
|
226
|
+
incoming_score = sum(1 for keyword in industrial_keywords if keyword in incoming_content)
|
|
227
|
+
|
|
228
|
+
if head_score > incoming_score:
|
|
229
|
+
return head_version
|
|
230
|
+
elif incoming_score > head_score:
|
|
231
|
+
return incoming_version
|
|
232
|
+
else:
|
|
233
|
+
# If equal, prefer the longer version
|
|
234
|
+
return head_version if len(head_content) > len(incoming_content) else incoming_version
|
|
235
|
+
|
|
236
|
+
def _resolve_button_conflicts(self, head_version: List[str], incoming_version: List[str]) -> List[str]:
|
|
237
|
+
"""Resolve Button.jsx conflicts - prefer shadcn re-export"""
|
|
238
|
+
head_content = ''.join(head_version)
|
|
239
|
+
incoming_content = ''.join(incoming_version)
|
|
240
|
+
|
|
241
|
+
# Prefer the shadcn re-export version
|
|
242
|
+
if 'ui/button' in head_content:
|
|
243
|
+
return head_version
|
|
244
|
+
elif 'ui/button' in incoming_content:
|
|
245
|
+
return incoming_version
|
|
246
|
+
else:
|
|
247
|
+
# If neither has shadcn, prefer the more complete implementation
|
|
248
|
+
return head_version if len(head_content) > len(incoming_content) else incoming_version
|
|
249
|
+
|
|
250
|
+
def verify_syntax(self, file_path: Path) -> bool:
|
|
251
|
+
"""Basic syntax verification for JS/JSX files"""
|
|
252
|
+
try:
|
|
253
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
254
|
+
content = f.read()
|
|
255
|
+
|
|
256
|
+
# Basic checks
|
|
257
|
+
if file_path.suffix in ['.jsx', '.js']:
|
|
258
|
+
# Check for unbalanced braces
|
|
259
|
+
open_braces = content.count('{')
|
|
260
|
+
close_braces = content.count('}')
|
|
261
|
+
if open_braces != close_braces:
|
|
262
|
+
logger.warning(f"Unbalanced braces in {file_path}")
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
# Check for unbalanced parentheses
|
|
266
|
+
open_parens = content.count('(')
|
|
267
|
+
close_parens = content.count(')')
|
|
268
|
+
if open_parens != close_parens:
|
|
269
|
+
logger.warning(f"Unbalanced parentheses in {file_path}")
|
|
270
|
+
return False
|
|
271
|
+
|
|
272
|
+
# Check for remaining conflict markers
|
|
273
|
+
if any(marker in content for marker in ['<<<<<<<', '=======', '>>>>>>>']):
|
|
274
|
+
logger.warning(f"Remaining conflict markers in {file_path}")
|
|
275
|
+
return False
|
|
276
|
+
|
|
277
|
+
return True
|
|
278
|
+
|
|
279
|
+
except Exception as e:
|
|
280
|
+
logger.error(f"Error verifying syntax for {file_path}: {e}")
|
|
281
|
+
return False
|
|
282
|
+
|
|
283
|
+
def run(self) -> Dict[str, any]:
|
|
284
|
+
"""Run the merge conflict cleaner"""
|
|
285
|
+
logger.info(f"Starting merge conflict cleanup in {self.base_path}")
|
|
286
|
+
|
|
287
|
+
# Find all files with conflicts
|
|
288
|
+
conflict_files = self.find_conflict_files()
|
|
289
|
+
|
|
290
|
+
if not conflict_files:
|
|
291
|
+
logger.info("No merge conflicts found!")
|
|
292
|
+
return {
|
|
293
|
+
'files_processed': 0,
|
|
294
|
+
'conflicts_resolved': 0,
|
|
295
|
+
'errors': [],
|
|
296
|
+
'success': True
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
logger.info(f"Found {len(conflict_files)} files with merge conflicts")
|
|
300
|
+
|
|
301
|
+
# Process each file
|
|
302
|
+
successful_files = []
|
|
303
|
+
failed_files = []
|
|
304
|
+
|
|
305
|
+
for file_path in conflict_files:
|
|
306
|
+
if self.clean_file(file_path):
|
|
307
|
+
if self.verify_syntax(file_path):
|
|
308
|
+
successful_files.append(file_path)
|
|
309
|
+
logger.info(f"✓ Successfully cleaned {file_path}")
|
|
310
|
+
else:
|
|
311
|
+
failed_files.append(file_path)
|
|
312
|
+
logger.error(f"✗ Syntax issues after cleaning {file_path}")
|
|
313
|
+
else:
|
|
314
|
+
failed_files.append(file_path)
|
|
315
|
+
logger.error(f"✗ Failed to clean {file_path}")
|
|
316
|
+
|
|
317
|
+
# Summary
|
|
318
|
+
logger.info(f"Cleanup complete!")
|
|
319
|
+
logger.info(f"Files processed: {self.files_processed}")
|
|
320
|
+
logger.info(f"Conflicts resolved: {self.conflicts_resolved}")
|
|
321
|
+
logger.info(f"Successful: {len(successful_files)}")
|
|
322
|
+
logger.info(f"Failed: {len(failed_files)}")
|
|
323
|
+
|
|
324
|
+
if failed_files:
|
|
325
|
+
logger.error("Failed files:")
|
|
326
|
+
for file_path in failed_files:
|
|
327
|
+
logger.error(f" - {file_path}")
|
|
328
|
+
|
|
329
|
+
if self.errors:
|
|
330
|
+
logger.error("Errors encountered:")
|
|
331
|
+
for error in self.errors:
|
|
332
|
+
logger.error(f" - {error}")
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
'files_processed': self.files_processed,
|
|
336
|
+
'conflicts_resolved': self.conflicts_resolved,
|
|
337
|
+
'successful_files': successful_files,
|
|
338
|
+
'failed_files': failed_files,
|
|
339
|
+
'errors': self.errors,
|
|
340
|
+
'success': len(failed_files) == 0
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
def main():
|
|
344
|
+
"""Main entry point"""
|
|
345
|
+
if len(sys.argv) != 2:
|
|
346
|
+
print("Usage: python merge-conflict-cleaner.py <path-to-src-directory>")
|
|
347
|
+
sys.exit(1)
|
|
348
|
+
|
|
349
|
+
src_path = sys.argv[1]
|
|
350
|
+
|
|
351
|
+
if not os.path.exists(src_path):
|
|
352
|
+
print(f"Error: Path {src_path} does not exist")
|
|
353
|
+
sys.exit(1)
|
|
354
|
+
|
|
355
|
+
cleaner = MergeConflictCleaner(src_path)
|
|
356
|
+
result = cleaner.run()
|
|
357
|
+
|
|
358
|
+
if result['success']:
|
|
359
|
+
print(f"\n✓ All merge conflicts resolved successfully!")
|
|
360
|
+
print(f" Files processed: {result['files_processed']}")
|
|
361
|
+
print(f" Conflicts resolved: {result['conflicts_resolved']}")
|
|
362
|
+
sys.exit(0)
|
|
363
|
+
else:
|
|
364
|
+
print(f"\n✗ Some issues occurred during cleanup")
|
|
365
|
+
print(f" Files processed: {result['files_processed']}")
|
|
366
|
+
print(f" Conflicts resolved: {result['conflicts_resolved']}")
|
|
367
|
+
print(f" Errors: {len(result['errors'])}")
|
|
368
|
+
sys.exit(1)
|
|
369
|
+
|
|
370
|
+
if __name__ == "__main__":
|
|
371
|
+
main()
|