@tinkcarlos/skillora 0.2.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/.claude/skills/.temp-skill-index.md +245 -0
- package/.claude/skills/SKILL.md +264 -0
- package/.claude/skills/api-scaffolding/SKILL.md +431 -0
- package/.claude/skills/api-scaffolding/agents/backend-architect.md +282 -0
- package/.claude/skills/api-scaffolding/agents/django-pro.md +144 -0
- package/.claude/skills/api-scaffolding/agents/fastapi-pro.md +156 -0
- package/.claude/skills/api-scaffolding/agents/graphql-architect.md +146 -0
- package/.claude/skills/api-scaffolding/skills/fastapi-templates/SKILL.md +171 -0
- package/.claude/skills/api-testing-observability/SKILL.md +583 -0
- package/.claude/skills/api-testing-observability/agents/api-documenter.md +146 -0
- package/.claude/skills/api-testing-observability/commands/api-mock.md +1320 -0
- package/.claude/skills/brainstorming/SKILL.md +283 -0
- package/.claude/skills/bug-fixing/SKILL.md +382 -0
- package/.claude/skills/bug-fixing/references/backend-guide.md +132 -0
- package/.claude/skills/bug-fixing/references/bug-guide.md +354 -0
- package/.claude/skills/bug-fixing/references/bug-record-template.md +134 -0
- package/.claude/skills/bug-fixing/references/bug-records.md +88 -0
- package/.claude/skills/bug-fixing/references/code-review-gate.md +81 -0
- package/.claude/skills/bug-fixing/references/common-bugs.md +140 -0
- package/.claude/skills/bug-fixing/references/complete-workflow.md +361 -0
- package/.claude/skills/bug-fixing/references/config-driven-fixes.md +136 -0
- package/.claude/skills/bug-fixing/references/context-isolation-protocol.md +268 -0
- package/.claude/skills/bug-fixing/references/cross-surface-regression.md +120 -0
- package/.claude/skills/bug-fixing/references/database-investigation.md +129 -0
- package/.claude/skills/bug-fixing/references/dependency-and-integrity-protocol.md +369 -0
- package/.claude/skills/bug-fixing/references/fix-completeness-checklist.md +239 -0
- package/.claude/skills/bug-fixing/references/frontend-guide.md +219 -0
- package/.claude/skills/bug-fixing/references/fullstack-joint-guide.md +123 -0
- package/.claude/skills/bug-fixing/references/functional-breakage.md +117 -0
- package/.claude/skills/bug-fixing/references/ide-lint-errors-guide.md +176 -0
- package/.claude/skills/bug-fixing/references/impact-analysis.md +511 -0
- package/.claude/skills/bug-fixing/references/investigation-checklist.md +263 -0
- package/.claude/skills/bug-fixing/references/knowledge-extraction-guide.md +531 -0
- package/.claude/skills/bug-fixing/references/knowledge-workflow.md +212 -0
- package/.claude/skills/bug-fixing/references/post-edit-quality-gate.md +30 -0
- package/.claude/skills/bug-fixing/references/python-env-and-testing.md +126 -0
- package/.claude/skills/bug-fixing/references/rca-guide.md +428 -0
- package/.claude/skills/bug-fixing/references/similar-bug-patterns.md +113 -0
- package/.claude/skills/bug-fixing/references/skill-delegation-guide.md +350 -0
- package/.claude/skills/bug-fixing/references/skill-orchestration.md +155 -0
- package/.claude/skills/bug-fixing/references/testing-strategy.md +350 -0
- package/.claude/skills/bug-fixing/references/tooling-build-scripts.md +162 -0
- package/.claude/skills/bug-fixing/references/user-input-validation.md +77 -0
- package/.claude/skills/bug-fixing/references/ux-patterns.md +158 -0
- package/.claude/skills/bug-fixing/references/windows-terminal-hygiene.md +106 -0
- package/.claude/skills/bug-fixing/references/zero-regression-matrix.md +239 -0
- package/.claude/skills/bug-fixing/references/zero-risk-protocol.md +102 -0
- package/.claude/skills/bug-fixing/scripts/format_code.py +611 -0
- package/.claude/skills/bug-fixing/scripts/generate_report_template.py +74 -0
- package/.claude/skills/bug-fixing/scripts/lint_check.py +816 -0
- package/.claude/skills/bug-fixing/scripts/requirements.txt +36 -0
- package/.claude/skills/cicd-pipeline/SKILL.md +300 -0
- package/.claude/skills/code-review/SKILL.md +535 -0
- package/.claude/skills/code-review/references/anti-pattern-scan.md +102 -0
- package/.claude/skills/code-review/references/automated-analysis.md +456 -0
- package/.claude/skills/code-review/references/backend-common-issues.md +589 -0
- package/.claude/skills/code-review/references/backend-expert-guide.md +415 -0
- package/.claude/skills/code-review/references/backend-review.md +868 -0
- package/.claude/skills/code-review/references/batch-processing-strategy.md +198 -0
- package/.claude/skills/code-review/references/call-chain-analysis-protocol.md +166 -0
- package/.claude/skills/code-review/references/common-patterns.md +321 -0
- package/.claude/skills/code-review/references/configuration-review.md +425 -0
- package/.claude/skills/code-review/references/control-flow-completeness.md +114 -0
- package/.claude/skills/code-review/references/database-review.md +298 -0
- package/.claude/skills/code-review/references/dependency-and-integrity-protocol.md +313 -0
- package/.claude/skills/code-review/references/external-standards.md +51 -0
- package/.claude/skills/code-review/references/feature-review.md +329 -0
- package/.claude/skills/code-review/references/file-review-template.md +326 -0
- package/.claude/skills/code-review/references/frontend-advanced.md +654 -0
- package/.claude/skills/code-review/references/frontend-common-issues.md +482 -0
- package/.claude/skills/code-review/references/frontend-expert-guide.md +342 -0
- package/.claude/skills/code-review/references/frontend-review.md +783 -0
- package/.claude/skills/code-review/references/fullstack-consistency.md +418 -0
- package/.claude/skills/code-review/references/fullstack-review.md +477 -0
- package/.claude/skills/code-review/references/functional-completeness.md +386 -0
- package/.claude/skills/code-review/references/hidden-bugs-detection.md +473 -0
- package/.claude/skills/code-review/references/ide-lint-errors-guide.md +173 -0
- package/.claude/skills/code-review/references/infrastructure-review.md +453 -0
- package/.claude/skills/code-review/references/iteration-review.md +264 -0
- package/.claude/skills/code-review/references/job-review.md +335 -0
- package/.claude/skills/code-review/references/layered-checklist-protocol.md +157 -0
- package/.claude/skills/code-review/references/logic-completeness.md +535 -0
- package/.claude/skills/code-review/references/mandatory-checklist.md +288 -0
- package/.claude/skills/code-review/references/multi-language-guide.md +800 -0
- package/.claude/skills/code-review/references/new-project-review.md +226 -0
- package/.claude/skills/code-review/references/non-code-files-review.md +451 -0
- package/.claude/skills/code-review/references/overlooked-issues.md +657 -0
- package/.claude/skills/code-review/references/platform-specific-review.md +195 -0
- package/.claude/skills/code-review/references/precision-analysis-protocol.md +260 -0
- package/.claude/skills/code-review/references/python-patterns.md +494 -0
- package/.claude/skills/code-review/references/rca-techniques.md +362 -0
- package/.claude/skills/code-review/references/report-template.md +430 -0
- package/.claude/skills/code-review/references/resource-limits-and-degradation.md +137 -0
- package/.claude/skills/code-review/references/review-dimensions.md +311 -0
- package/.claude/skills/code-review/references/review-guide.md +202 -0
- package/.claude/skills/code-review/references/review-knowledge-workflow.md +257 -0
- package/.claude/skills/code-review/references/review-progress-tracker-protocol.md +172 -0
- package/.claude/skills/code-review/references/review-record-template.md +195 -0
- package/.claude/skills/code-review/references/skill-orchestration.md +143 -0
- package/.claude/skills/code-review/references/ui-ux-review.md +470 -0
- package/.claude/skills/containerization/SKILL.md +313 -0
- package/.claude/skills/database-migrations/agents/database-admin.md +142 -0
- package/.claude/skills/database-migrations/agents/database-optimizer.md +144 -0
- package/.claude/skills/database-migrations/commands/migration-observability.md +408 -0
- package/.claude/skills/database-migrations/commands/sql-migrations.md +492 -0
- package/.claude/skills/finishing-a-development-branch/SKILL.md +319 -0
- package/.claude/skills/frontend-design/LICENSE.txt +177 -0
- package/.claude/skills/frontend-design/SKILL.md +587 -0
- package/.claude/skills/frontend-design/references/color-consistency.md +487 -0
- package/.claude/skills/frontend-design/references/color-palettes-full.md +657 -0
- package/.claude/skills/frontend-design/references/design-system-generator.md +285 -0
- package/.claude/skills/frontend-design/references/font-pairings-full.md +705 -0
- package/.claude/skills/frontend-design/references/industry-anti-patterns.md +281 -0
- package/.claude/skills/frontend-design/references/layout-anti-patterns.md +582 -0
- package/.claude/skills/frontend-design/references/motion-patterns.md +659 -0
- package/.claude/skills/frontend-design/references/pre-delivery-checklist.md +153 -0
- package/.claude/skills/frontend-design/references/responsive-design.md +555 -0
- package/.claude/skills/frontend-design/references/style-modification-rules.md +335 -0
- package/.claude/skills/frontend-design/references/ui-styles-full.md +383 -0
- package/.claude/skills/frontend-design/references/ui-styles-rating.md +191 -0
- package/.claude/skills/frontend-design/references/ux-guidelines.md +640 -0
- package/.claude/skills/fullstack-developer/SKILL.md +512 -0
- package/.claude/skills/fullstack-developer/references/api-contract-guide.md +312 -0
- package/.claude/skills/fullstack-developer/references/api-response-patterns.md +223 -0
- package/.claude/skills/fullstack-developer/references/async-patterns.md +220 -0
- package/.claude/skills/fullstack-developer/references/bug-prevention.md +914 -0
- package/.claude/skills/fullstack-developer/references/code-quality-checklist.md +271 -0
- package/.claude/skills/fullstack-developer/references/complete-development-workflow.md +278 -0
- package/.claude/skills/fullstack-developer/references/context-isolation-protocol.md +256 -0
- package/.claude/skills/fullstack-developer/references/database-migration.md +331 -0
- package/.claude/skills/fullstack-developer/references/dependency-and-integrity-protocol.md +390 -0
- package/.claude/skills/fullstack-developer/references/development-phases.md +333 -0
- package/.claude/skills/fullstack-developer/references/expert-guide.md +214 -0
- package/.claude/skills/fullstack-developer/references/file-import-patterns.md +114 -0
- package/.claude/skills/fullstack-developer/references/graceful-degradation-patterns.md +78 -0
- package/.claude/skills/fullstack-developer/references/ide-lint-errors-guide.md +183 -0
- package/.claude/skills/fullstack-developer/references/integration-testing.md +301 -0
- package/.claude/skills/fullstack-developer/references/mock-api-patterns.md +307 -0
- package/.claude/skills/fullstack-developer/references/phase-gate-template.md +249 -0
- package/.claude/skills/fullstack-developer/references/post-edit-quality-gate.md +30 -0
- package/.claude/skills/fullstack-developer/references/python-engineering.md +79 -0
- package/.claude/skills/fullstack-developer/references/skill-orchestration.md +214 -0
- package/.claude/skills/fullstack-developer/references/skill-router-table.md +304 -0
- package/.claude/skills/fullstack-developer/references/state-sync.md +217 -0
- package/.claude/skills/fullstack-developer/references/ui-testing-checklist.md +292 -0
- package/.claude/skills/fullstack-developer/scripts/format_code.py +611 -0
- package/.claude/skills/fullstack-developer/scripts/lint_check.py +816 -0
- package/.claude/skills/fullstack-developer/scripts/requirements.txt +36 -0
- package/.claude/skills/performance-optimization/SKILL.md +250 -0
- package/.claude/skills/product-requirements/SKILL.md +357 -0
- package/.claude/skills/product-requirements/references/acceptance-criteria.md +335 -0
- package/.claude/skills/product-requirements/references/answer-first-questioning-protocol.md +299 -0
- package/.claude/skills/product-requirements/references/competitive-analysis-guide.md +183 -0
- package/.claude/skills/product-requirements/references/document-accuracy-protocol.md +253 -0
- package/.claude/skills/product-requirements/references/document-management-protocol.md +278 -0
- package/.claude/skills/product-requirements/references/external-standards.md +62 -0
- package/.claude/skills/product-requirements/references/feature-spec-template.md +359 -0
- package/.claude/skills/product-requirements/references/knowledge-acquisition-protocol.md +251 -0
- package/.claude/skills/product-requirements/references/plan-execution-protocol.md +334 -0
- package/.claude/skills/product-requirements/references/plan-generation-protocol.md +264 -0
- package/.claude/skills/product-requirements/references/prioritization-frameworks.md +80 -0
- package/.claude/skills/product-requirements/references/requirement-decomposition-protocol.md +291 -0
- package/.claude/skills/product-requirements/references/user-story-examples.md +297 -0
- package/.claude/skills/product-requirements/references/workflow-templates.md +266 -0
- package/.claude/skills/react-best-practices/SKILL.md +198 -0
- package/.claude/skills/react-best-practices/references/advanced-patterns.md +94 -0
- package/.claude/skills/react-best-practices/references/bundle-optimization.md +182 -0
- package/.claude/skills/react-best-practices/references/client-data-fetching.md +112 -0
- package/.claude/skills/react-best-practices/references/complete-guide.md +2249 -0
- package/.claude/skills/react-best-practices/references/eliminating-waterfalls.md +169 -0
- package/.claude/skills/react-best-practices/references/javascript-performance.md +256 -0
- package/.claude/skills/react-best-practices/references/rendering-performance.md +230 -0
- package/.claude/skills/react-best-practices/references/rerender-optimization.md +214 -0
- package/.claude/skills/react-best-practices/references/server-performance.md +182 -0
- package/.claude/skills/security-audit/SKILL.md +226 -0
- package/.claude/skills/shared-references/advanced-debugging-techniques.md +186 -0
- package/.claude/skills/shared-references/code-quality-checklist.md +218 -0
- package/.claude/skills/shared-references/code-review-efficiency-guide.md +125 -0
- package/.claude/skills/shared-references/mcp-dependency-compatibility-protocol.md +276 -0
- package/.claude/skills/shared-references/skill-call-graph.md +230 -0
- package/.claude/skills/shared-references/skill-orchestration-protocol.md +281 -0
- package/.claude/skills/shared-references/subagent-dispatch-templates.md +199 -0
- package/.claude/skills/skill-expert-skills/LICENSE.txt +204 -0
- package/.claude/skills/skill-expert-skills/QUICK_NAVIGATION.md +374 -0
- package/.claude/skills/skill-expert-skills/SKILL.md +247 -0
- package/.claude/skills/skill-expert-skills/docs/_index.md +91 -0
- package/.claude/skills/skill-expert-skills/references/deep-research-methodology.md +389 -0
- package/.claude/skills/skill-expert-skills/references/docs-generation-workflow.md +398 -0
- package/.claude/skills/skill-expert-skills/references/domain-expertise-protocol.md +343 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/_index.md +54 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/backend-expertise.md +517 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/bug-fixing-expertise.md +363 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/code-review-expertise.md +392 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge/frontend-expertise.md +410 -0
- package/.claude/skills/skill-expert-skills/references/domain-knowledge-template.md +503 -0
- package/.claude/skills/skill-expert-skills/references/examples.md +782 -0
- package/.claude/skills/skill-expert-skills/references/integration-examples.md +655 -0
- package/.claude/skills/skill-expert-skills/references/knowledge-validation-checklist.md +246 -0
- package/.claude/skills/skill-expert-skills/references/latest-knowledge-acquisition.md +461 -0
- package/.claude/skills/skill-expert-skills/references/mcp-tools-guide.md +439 -0
- package/.claude/skills/skill-expert-skills/references/official-best-practices.md +616 -0
- package/.claude/skills/skill-expert-skills/references/patterns.md +218 -0
- package/.claude/skills/skill-expert-skills/references/plugin-skills-guide.md +432 -0
- package/.claude/skills/skill-expert-skills/references/requirement-elicitation-protocol.md +290 -0
- package/.claude/skills/skill-expert-skills/references/skill-creator-SKILL.md +353 -0
- package/.claude/skills/skill-expert-skills/references/skill-templates.md +583 -0
- package/.claude/skills/skill-expert-skills/references/skills-knowledge-base.md +561 -0
- package/.claude/skills/skill-expert-skills/references/tools-guide.md +379 -0
- package/.claude/skills/skill-expert-skills/references/troubleshooting.md +378 -0
- package/.claude/skills/skill-expert-skills/references/universality-guide.md +205 -0
- package/.claude/skills/skill-expert-skills/references/writing-style-guide.md +466 -0
- package/.claude/skills/skill-expert-skills/scripts/__pycache__/quick_validate.cpython-313.pyc +0 -0
- package/.claude/skills/skill-expert-skills/scripts/__pycache__/universal_validate.cpython-313.pyc +0 -0
- package/.claude/skills/skill-expert-skills/scripts/analyze_trigger.py +425 -0
- package/.claude/skills/skill-expert-skills/scripts/diff_with_official.py +188 -0
- package/.claude/skills/skill-expert-skills/scripts/init_skill.py +349 -0
- package/.claude/skills/skill-expert-skills/scripts/package_skill.py +156 -0
- package/.claude/skills/skill-expert-skills/scripts/quick_validate.py +493 -0
- package/.claude/skills/skill-expert-skills/scripts/requirements.txt +2 -0
- package/.claude/skills/skill-expert-skills/scripts/universal_validate.py +182 -0
- package/.claude/skills/skill-expert-skills/scripts/upgrade_skill.py +431 -0
- package/.claude/skills/subagent-driven-development/SKILL.md +268 -0
- package/.claude/skills/test-driven-development/SKILL.md +246 -0
- package/.claude/skills/test-driven-development/references/testing-anti-patterns.md +192 -0
- package/.claude/skills/using-git-worktrees/SKILL.md +266 -0
- package/.claude/skills/using-skillstack/SKILL.md +127 -0
- package/.claude/skills/vercel-deploy/SKILL.md +166 -0
- package/.claude/skills/vercel-deploy/scripts/deploy.sh +249 -0
- package/.claude/skills/verification-before-completion/SKILL.md +305 -0
- package/.claude/skills/writing-plans/SKILL.md +259 -0
- package/README.md +69 -0
- package/bin/cli.js +468 -0
- package/lib/init.js +333 -0
- package/package.json +29 -0
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Code Formatting Script - Auto-format code files after modification.
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- Supports Python (ruff/black), TypeScript/JavaScript (prettier), Go, Rust
|
|
7
|
+
- Auto-detects and suggests missing formatters
|
|
8
|
+
- Parallel processing for multiple files
|
|
9
|
+
- JSON output for CI/CD integration
|
|
10
|
+
- Respects project config files (.prettierrc, pyproject.toml, etc.)
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
python format_code.py <file_path> [--check-only] [--json]
|
|
14
|
+
python format_code.py <file1> <file2> ... # Multiple files (parallel)
|
|
15
|
+
python format_code.py --dir <directory> # Format directory
|
|
16
|
+
python format_code.py --check-deps # Check dependencies
|
|
17
|
+
|
|
18
|
+
Exit codes:
|
|
19
|
+
0 - Success (formatted or already formatted)
|
|
20
|
+
1 - Formatting failed or file not found
|
|
21
|
+
2 - Formatter not available (install required)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import argparse
|
|
27
|
+
import subprocess
|
|
28
|
+
import sys
|
|
29
|
+
import os
|
|
30
|
+
import json as json_module
|
|
31
|
+
from pathlib import Path
|
|
32
|
+
from typing import List, Tuple, Optional, Dict, Any
|
|
33
|
+
from dataclasses import dataclass, asdict
|
|
34
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
35
|
+
import threading
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Configure stdout/stderr encoding for Windows
|
|
39
|
+
def _configure_stdio() -> None:
|
|
40
|
+
"""Ensure UTF-8 encoding for stdout/stderr on Windows"""
|
|
41
|
+
if sys.platform == 'win32':
|
|
42
|
+
os.environ.setdefault('PYTHONIOENCODING', 'utf-8')
|
|
43
|
+
for stream in (sys.stdout, sys.stderr):
|
|
44
|
+
try:
|
|
45
|
+
stream.reconfigure(encoding='utf-8', errors='replace')
|
|
46
|
+
except Exception:
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
_configure_stdio()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class FormatResult:
|
|
54
|
+
"""Result of formatting a single file"""
|
|
55
|
+
file_path: str
|
|
56
|
+
success: bool
|
|
57
|
+
changed: bool
|
|
58
|
+
message: str
|
|
59
|
+
formatter_used: Optional[str] = None
|
|
60
|
+
|
|
61
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
62
|
+
return asdict(self)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class DependencyStatus:
|
|
67
|
+
"""Status of a formatter dependency"""
|
|
68
|
+
name: str
|
|
69
|
+
available: bool
|
|
70
|
+
version: Optional[str] = None
|
|
71
|
+
install_cmd: Optional[str] = None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class CodeFormatter:
|
|
75
|
+
"""Multi-language code formatter with fallback support"""
|
|
76
|
+
|
|
77
|
+
# File extension to language mapping
|
|
78
|
+
EXTENSION_MAP = {
|
|
79
|
+
# Python
|
|
80
|
+
'.py': 'python', '.pyw': 'python', '.pyi': 'python',
|
|
81
|
+
# JavaScript/TypeScript
|
|
82
|
+
'.ts': 'typescript', '.tsx': 'typescript',
|
|
83
|
+
'.js': 'javascript', '.jsx': 'javascript',
|
|
84
|
+
'.mjs': 'javascript', '.cjs': 'javascript',
|
|
85
|
+
# Web
|
|
86
|
+
'.json': 'json', '.css': 'css', '.scss': 'scss', '.less': 'less',
|
|
87
|
+
'.html': 'html', '.vue': 'vue', '.svelte': 'svelte',
|
|
88
|
+
'.yaml': 'yaml', '.yml': 'yaml', '.md': 'markdown',
|
|
89
|
+
# Other languages
|
|
90
|
+
'.go': 'go', '.rs': 'rust', '.sql': 'sql',
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# Formatter install commands
|
|
94
|
+
INSTALL_COMMANDS = {
|
|
95
|
+
'ruff': 'pip install ruff',
|
|
96
|
+
'black': 'pip install black',
|
|
97
|
+
'prettier': 'npm install -g prettier',
|
|
98
|
+
'gofmt': 'Included with Go installation',
|
|
99
|
+
'rustfmt': 'rustup component add rustfmt',
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def __init__(self, verbose: bool = False, max_workers: int = 4):
|
|
103
|
+
self.verbose = verbose
|
|
104
|
+
self.max_workers = max_workers
|
|
105
|
+
self._formatter_cache: Dict[str, bool] = {}
|
|
106
|
+
self._version_cache: Dict[str, str] = {}
|
|
107
|
+
self._cache_lock = threading.Lock()
|
|
108
|
+
|
|
109
|
+
def _log(self, message: str) -> None:
|
|
110
|
+
if self.verbose:
|
|
111
|
+
print(f"[FORMAT] {message}", file=sys.stderr)
|
|
112
|
+
|
|
113
|
+
def _check_command(self, cmd: str) -> bool:
|
|
114
|
+
"""Check if a command is available (thread-safe)"""
|
|
115
|
+
with self._cache_lock:
|
|
116
|
+
if cmd in self._formatter_cache:
|
|
117
|
+
return self._formatter_cache[cmd]
|
|
118
|
+
|
|
119
|
+
try:
|
|
120
|
+
check_cmd = 'where' if sys.platform == 'win32' else 'which'
|
|
121
|
+
result = subprocess.run(
|
|
122
|
+
[check_cmd, cmd],
|
|
123
|
+
capture_output=True,
|
|
124
|
+
text=True,
|
|
125
|
+
timeout=5
|
|
126
|
+
)
|
|
127
|
+
available = result.returncode == 0
|
|
128
|
+
except Exception:
|
|
129
|
+
available = False
|
|
130
|
+
|
|
131
|
+
with self._cache_lock:
|
|
132
|
+
self._formatter_cache[cmd] = available
|
|
133
|
+
return available
|
|
134
|
+
|
|
135
|
+
def _get_version(self, cmd: str, version_flag: str = '--version') -> Optional[str]:
|
|
136
|
+
"""Get version of a command"""
|
|
137
|
+
with self._cache_lock:
|
|
138
|
+
if cmd in self._version_cache:
|
|
139
|
+
return self._version_cache[cmd]
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
result = subprocess.run(
|
|
143
|
+
[cmd, version_flag],
|
|
144
|
+
capture_output=True,
|
|
145
|
+
text=True,
|
|
146
|
+
timeout=5
|
|
147
|
+
)
|
|
148
|
+
if result.returncode == 0:
|
|
149
|
+
version = result.stdout.strip().split('\n')[0]
|
|
150
|
+
with self._cache_lock:
|
|
151
|
+
self._version_cache[cmd] = version
|
|
152
|
+
return version
|
|
153
|
+
except Exception:
|
|
154
|
+
pass
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
def check_dependencies(self) -> List[DependencyStatus]:
|
|
158
|
+
"""Check all formatter dependencies"""
|
|
159
|
+
deps = []
|
|
160
|
+
|
|
161
|
+
# Python formatters
|
|
162
|
+
for name in ['ruff', 'black']:
|
|
163
|
+
available = self._check_command(name)
|
|
164
|
+
deps.append(DependencyStatus(
|
|
165
|
+
name=name,
|
|
166
|
+
available=available,
|
|
167
|
+
version=self._get_version(name) if available else None,
|
|
168
|
+
install_cmd=self.INSTALL_COMMANDS.get(name)
|
|
169
|
+
))
|
|
170
|
+
|
|
171
|
+
# Node.js formatters
|
|
172
|
+
for name in ['prettier']:
|
|
173
|
+
# Check both global and npx
|
|
174
|
+
available = self._check_command(name) or self._check_command('npx')
|
|
175
|
+
deps.append(DependencyStatus(
|
|
176
|
+
name=name,
|
|
177
|
+
available=available,
|
|
178
|
+
version=self._get_version('prettier') if self._check_command('prettier') else 'via npx',
|
|
179
|
+
install_cmd=self.INSTALL_COMMANDS.get(name)
|
|
180
|
+
))
|
|
181
|
+
|
|
182
|
+
# Go formatter
|
|
183
|
+
available = self._check_command('gofmt')
|
|
184
|
+
deps.append(DependencyStatus(
|
|
185
|
+
name='gofmt',
|
|
186
|
+
available=available,
|
|
187
|
+
version=self._get_version('go', 'version') if available else None,
|
|
188
|
+
install_cmd=self.INSTALL_COMMANDS.get('gofmt')
|
|
189
|
+
))
|
|
190
|
+
|
|
191
|
+
# Rust formatter
|
|
192
|
+
available = self._check_command('rustfmt')
|
|
193
|
+
deps.append(DependencyStatus(
|
|
194
|
+
name='rustfmt',
|
|
195
|
+
available=available,
|
|
196
|
+
version=self._get_version('rustfmt') if available else None,
|
|
197
|
+
install_cmd=self.INSTALL_COMMANDS.get('rustfmt')
|
|
198
|
+
))
|
|
199
|
+
|
|
200
|
+
return deps
|
|
201
|
+
|
|
202
|
+
def _run_formatter(self, cmd: List[str], file_path: str, timeout: int = 30) -> Tuple[bool, str]:
|
|
203
|
+
"""Run a formatter command and return (success, message)"""
|
|
204
|
+
try:
|
|
205
|
+
self._log(f"Running: {' '.join(cmd)}")
|
|
206
|
+
result = subprocess.run(
|
|
207
|
+
cmd,
|
|
208
|
+
capture_output=True,
|
|
209
|
+
text=True,
|
|
210
|
+
encoding='utf-8',
|
|
211
|
+
errors='replace',
|
|
212
|
+
timeout=timeout,
|
|
213
|
+
cwd=Path(file_path).parent # Run in file's directory for config detection
|
|
214
|
+
)
|
|
215
|
+
if result.returncode == 0:
|
|
216
|
+
return True, "Formatted successfully"
|
|
217
|
+
else:
|
|
218
|
+
error_msg = result.stderr.strip() or result.stdout.strip() or "Unknown error"
|
|
219
|
+
# Truncate long error messages
|
|
220
|
+
if len(error_msg) > 200:
|
|
221
|
+
error_msg = error_msg[:200] + "..."
|
|
222
|
+
return False, f"Formatter error: {error_msg}"
|
|
223
|
+
except subprocess.TimeoutExpired:
|
|
224
|
+
return False, f"Formatter timeout ({timeout}s)"
|
|
225
|
+
except Exception as e:
|
|
226
|
+
return False, f"Failed to run formatter: {e}"
|
|
227
|
+
|
|
228
|
+
def _format_python(self, file_path: str, check_only: bool = False) -> FormatResult:
|
|
229
|
+
"""Format Python file using ruff (preferred) or black"""
|
|
230
|
+
path = Path(file_path).resolve()
|
|
231
|
+
|
|
232
|
+
# Try ruff first (faster, more features)
|
|
233
|
+
if self._check_command('ruff'):
|
|
234
|
+
cmd = ['ruff', 'format']
|
|
235
|
+
if check_only:
|
|
236
|
+
cmd.append('--check')
|
|
237
|
+
cmd.append(str(path))
|
|
238
|
+
|
|
239
|
+
success, message = self._run_formatter(cmd, file_path)
|
|
240
|
+
return FormatResult(
|
|
241
|
+
file_path=str(path),
|
|
242
|
+
success=success,
|
|
243
|
+
changed=success and not check_only,
|
|
244
|
+
message=message,
|
|
245
|
+
formatter_used='ruff'
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
# Fall back to black
|
|
249
|
+
if self._check_command('black'):
|
|
250
|
+
cmd = ['black']
|
|
251
|
+
if check_only:
|
|
252
|
+
cmd.append('--check')
|
|
253
|
+
cmd.append(str(path))
|
|
254
|
+
|
|
255
|
+
success, message = self._run_formatter(cmd, file_path)
|
|
256
|
+
return FormatResult(
|
|
257
|
+
file_path=str(path),
|
|
258
|
+
success=success,
|
|
259
|
+
changed=success and not check_only,
|
|
260
|
+
message=message,
|
|
261
|
+
formatter_used='black'
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
return FormatResult(
|
|
265
|
+
file_path=str(path),
|
|
266
|
+
success=False,
|
|
267
|
+
changed=False,
|
|
268
|
+
message="No Python formatter available. Install: pip install ruff"
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
def _format_js_ts(self, file_path: str, check_only: bool = False) -> FormatResult:
|
|
272
|
+
"""Format JavaScript/TypeScript using prettier"""
|
|
273
|
+
path = Path(file_path).resolve()
|
|
274
|
+
|
|
275
|
+
prettier_cmd = None
|
|
276
|
+
if self._check_command('prettier'):
|
|
277
|
+
prettier_cmd = ['prettier']
|
|
278
|
+
elif self._check_command('npx'):
|
|
279
|
+
prettier_cmd = ['npx', '--yes', 'prettier']
|
|
280
|
+
|
|
281
|
+
if prettier_cmd:
|
|
282
|
+
cmd = prettier_cmd.copy()
|
|
283
|
+
if check_only:
|
|
284
|
+
cmd.append('--check')
|
|
285
|
+
else:
|
|
286
|
+
cmd.append('--write')
|
|
287
|
+
cmd.append(str(path))
|
|
288
|
+
|
|
289
|
+
success, message = self._run_formatter(cmd, file_path)
|
|
290
|
+
return FormatResult(
|
|
291
|
+
file_path=str(path),
|
|
292
|
+
success=success,
|
|
293
|
+
changed=success and not check_only,
|
|
294
|
+
message=message,
|
|
295
|
+
formatter_used='prettier'
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
return FormatResult(
|
|
299
|
+
file_path=str(path),
|
|
300
|
+
success=False,
|
|
301
|
+
changed=False,
|
|
302
|
+
message="No JS/TS formatter available. Install: npm install -g prettier"
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
def _format_go(self, file_path: str, check_only: bool = False) -> FormatResult:
|
|
306
|
+
"""Format Go file using gofmt"""
|
|
307
|
+
path = Path(file_path).resolve()
|
|
308
|
+
|
|
309
|
+
if self._check_command('gofmt'):
|
|
310
|
+
if check_only:
|
|
311
|
+
# gofmt -d returns diff, non-empty means needs formatting
|
|
312
|
+
cmd = ['gofmt', '-d', str(path)]
|
|
313
|
+
success, message = self._run_formatter(cmd, file_path)
|
|
314
|
+
return FormatResult(
|
|
315
|
+
file_path=str(path),
|
|
316
|
+
success=True,
|
|
317
|
+
changed=bool(message and 'diff' not in message.lower()),
|
|
318
|
+
message="Check completed",
|
|
319
|
+
formatter_used='gofmt'
|
|
320
|
+
)
|
|
321
|
+
else:
|
|
322
|
+
cmd = ['gofmt', '-w', str(path)]
|
|
323
|
+
success, message = self._run_formatter(cmd, file_path)
|
|
324
|
+
return FormatResult(
|
|
325
|
+
file_path=str(path),
|
|
326
|
+
success=success,
|
|
327
|
+
changed=success,
|
|
328
|
+
message=message,
|
|
329
|
+
formatter_used='gofmt'
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
return FormatResult(
|
|
333
|
+
file_path=str(path),
|
|
334
|
+
success=False,
|
|
335
|
+
changed=False,
|
|
336
|
+
message="gofmt not available. Install Go from https://golang.org/"
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def _format_rust(self, file_path: str, check_only: bool = False) -> FormatResult:
|
|
340
|
+
"""Format Rust file using rustfmt"""
|
|
341
|
+
path = Path(file_path).resolve()
|
|
342
|
+
|
|
343
|
+
if self._check_command('rustfmt'):
|
|
344
|
+
cmd = ['rustfmt']
|
|
345
|
+
if check_only:
|
|
346
|
+
cmd.append('--check')
|
|
347
|
+
cmd.append(str(path))
|
|
348
|
+
|
|
349
|
+
success, message = self._run_formatter(cmd, file_path)
|
|
350
|
+
return FormatResult(
|
|
351
|
+
file_path=str(path),
|
|
352
|
+
success=success,
|
|
353
|
+
changed=success and not check_only,
|
|
354
|
+
message=message,
|
|
355
|
+
formatter_used='rustfmt'
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
return FormatResult(
|
|
359
|
+
file_path=str(path),
|
|
360
|
+
success=False,
|
|
361
|
+
changed=False,
|
|
362
|
+
message="rustfmt not available. Install: rustup component add rustfmt"
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
def _format_json(self, file_path: str, check_only: bool = False) -> FormatResult:
|
|
366
|
+
"""Format JSON using prettier or Python json module"""
|
|
367
|
+
path = Path(file_path).resolve()
|
|
368
|
+
|
|
369
|
+
# Try prettier first
|
|
370
|
+
prettier_result = self._format_js_ts(file_path, check_only)
|
|
371
|
+
if prettier_result.success:
|
|
372
|
+
return prettier_result
|
|
373
|
+
|
|
374
|
+
# Fall back to Python json module
|
|
375
|
+
try:
|
|
376
|
+
content = path.read_text(encoding='utf-8')
|
|
377
|
+
parsed = json_module.loads(content)
|
|
378
|
+
formatted = json_module.dumps(parsed, indent=2, ensure_ascii=False) + '\n'
|
|
379
|
+
|
|
380
|
+
if check_only:
|
|
381
|
+
changed = content != formatted
|
|
382
|
+
return FormatResult(
|
|
383
|
+
file_path=str(path),
|
|
384
|
+
success=True,
|
|
385
|
+
changed=changed,
|
|
386
|
+
message="Check passed" if not changed else "File needs formatting",
|
|
387
|
+
formatter_used='python-json'
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
if content != formatted:
|
|
391
|
+
path.write_text(formatted, encoding='utf-8')
|
|
392
|
+
return FormatResult(
|
|
393
|
+
file_path=str(path),
|
|
394
|
+
success=True,
|
|
395
|
+
changed=True,
|
|
396
|
+
message="Formatted successfully",
|
|
397
|
+
formatter_used='python-json'
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
return FormatResult(
|
|
401
|
+
file_path=str(path),
|
|
402
|
+
success=True,
|
|
403
|
+
changed=False,
|
|
404
|
+
message="Already formatted",
|
|
405
|
+
formatter_used='python-json'
|
|
406
|
+
)
|
|
407
|
+
except Exception as e:
|
|
408
|
+
return FormatResult(
|
|
409
|
+
file_path=str(path),
|
|
410
|
+
success=False,
|
|
411
|
+
changed=False,
|
|
412
|
+
message=f"JSON format error: {e}"
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
def format_file(self, file_path: str, check_only: bool = False) -> FormatResult:
|
|
416
|
+
"""Format a single file based on its extension"""
|
|
417
|
+
path = Path(file_path)
|
|
418
|
+
|
|
419
|
+
if not path.exists():
|
|
420
|
+
return FormatResult(
|
|
421
|
+
file_path=str(path),
|
|
422
|
+
success=False,
|
|
423
|
+
changed=False,
|
|
424
|
+
message=f"File not found: {file_path}"
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
ext = path.suffix.lower()
|
|
428
|
+
language = self.EXTENSION_MAP.get(ext)
|
|
429
|
+
|
|
430
|
+
if language == 'python':
|
|
431
|
+
return self._format_python(file_path, check_only)
|
|
432
|
+
elif language in ('typescript', 'javascript', 'css', 'scss', 'less',
|
|
433
|
+
'markdown', 'html', 'vue', 'svelte', 'yaml'):
|
|
434
|
+
return self._format_js_ts(file_path, check_only)
|
|
435
|
+
elif language == 'json':
|
|
436
|
+
return self._format_json(file_path, check_only)
|
|
437
|
+
elif language == 'go':
|
|
438
|
+
return self._format_go(file_path, check_only)
|
|
439
|
+
elif language == 'rust':
|
|
440
|
+
return self._format_rust(file_path, check_only)
|
|
441
|
+
elif language == 'sql':
|
|
442
|
+
# SQL formatting via prettier-plugin-sql (if available)
|
|
443
|
+
return self._format_js_ts(file_path, check_only)
|
|
444
|
+
else:
|
|
445
|
+
return FormatResult(
|
|
446
|
+
file_path=str(path),
|
|
447
|
+
success=True,
|
|
448
|
+
changed=False,
|
|
449
|
+
message=f"No formatter configured for extension: {ext}"
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
def format_files(self, file_paths: List[str], check_only: bool = False) -> List[FormatResult]:
|
|
453
|
+
"""Format multiple files (parallel processing)"""
|
|
454
|
+
if len(file_paths) == 1:
|
|
455
|
+
return [self.format_file(file_paths[0], check_only)]
|
|
456
|
+
|
|
457
|
+
results = []
|
|
458
|
+
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
|
|
459
|
+
future_to_path = {
|
|
460
|
+
executor.submit(self.format_file, path, check_only): path
|
|
461
|
+
for path in file_paths
|
|
462
|
+
}
|
|
463
|
+
for future in as_completed(future_to_path):
|
|
464
|
+
result = future.result()
|
|
465
|
+
results.append(result)
|
|
466
|
+
self._log(f"{result.file_path}: {result.message}")
|
|
467
|
+
|
|
468
|
+
# Sort by original order
|
|
469
|
+
path_order = {path: i for i, path in enumerate(file_paths)}
|
|
470
|
+
results.sort(key=lambda r: path_order.get(r.file_path, 999))
|
|
471
|
+
return results
|
|
472
|
+
|
|
473
|
+
def format_directory(self, dir_path: str, check_only: bool = False,
|
|
474
|
+
extensions: Optional[List[str]] = None) -> List[FormatResult]:
|
|
475
|
+
"""Format all supported files in a directory"""
|
|
476
|
+
path = Path(dir_path)
|
|
477
|
+
if not path.exists():
|
|
478
|
+
return [FormatResult(
|
|
479
|
+
file_path=str(path),
|
|
480
|
+
success=False,
|
|
481
|
+
changed=False,
|
|
482
|
+
message=f"Directory not found: {dir_path}"
|
|
483
|
+
)]
|
|
484
|
+
|
|
485
|
+
if extensions is None:
|
|
486
|
+
extensions = list(self.EXTENSION_MAP.keys())
|
|
487
|
+
|
|
488
|
+
files = []
|
|
489
|
+
for ext in extensions:
|
|
490
|
+
files.extend(path.rglob(f'*{ext}'))
|
|
491
|
+
|
|
492
|
+
# Filter out common exclusions
|
|
493
|
+
exclude_patterns = [
|
|
494
|
+
'node_modules', '__pycache__', '.git', 'dist', 'build',
|
|
495
|
+
'venv', '.venv', 'target', '.next', '.nuxt', 'coverage'
|
|
496
|
+
]
|
|
497
|
+
files = [f for f in files if not any(p in str(f) for p in exclude_patterns)]
|
|
498
|
+
|
|
499
|
+
return self.format_files([str(f) for f in files], check_only)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def print_dependencies(deps: List[DependencyStatus]) -> None:
|
|
503
|
+
"""Print dependency status"""
|
|
504
|
+
print("\n" + "=" * 60)
|
|
505
|
+
print("🔧 FORMATTER DEPENDENCIES")
|
|
506
|
+
print("=" * 60)
|
|
507
|
+
|
|
508
|
+
for dep in deps:
|
|
509
|
+
status = "✅" if dep.available else "❌"
|
|
510
|
+
version = f" ({dep.version})" if dep.version else ""
|
|
511
|
+
print(f" {status} {dep.name}{version}")
|
|
512
|
+
if not dep.available and dep.install_cmd:
|
|
513
|
+
print(f" Install: {dep.install_cmd}")
|
|
514
|
+
|
|
515
|
+
print("=" * 60)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def print_summary(results: List[FormatResult], json_output: bool = False) -> None:
|
|
519
|
+
"""Print a summary of formatting results"""
|
|
520
|
+
if json_output:
|
|
521
|
+
output = {
|
|
522
|
+
'results': [r.to_dict() for r in results],
|
|
523
|
+
'summary': {
|
|
524
|
+
'total': len(results),
|
|
525
|
+
'success': sum(1 for r in results if r.success),
|
|
526
|
+
'changed': sum(1 for r in results if r.changed),
|
|
527
|
+
'failed': sum(1 for r in results if not r.success)
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
print(json_module.dumps(output, indent=2, ensure_ascii=False))
|
|
531
|
+
return
|
|
532
|
+
|
|
533
|
+
print("\n" + "=" * 60)
|
|
534
|
+
print("📋 FORMATTING SUMMARY")
|
|
535
|
+
print("=" * 60)
|
|
536
|
+
|
|
537
|
+
success_count = sum(1 for r in results if r.success)
|
|
538
|
+
changed_count = sum(1 for r in results if r.changed)
|
|
539
|
+
failed_count = len(results) - success_count
|
|
540
|
+
|
|
541
|
+
for result in results:
|
|
542
|
+
status = "✅" if result.success else "❌"
|
|
543
|
+
change = "(changed)" if result.changed else ""
|
|
544
|
+
formatter = f"[{result.formatter_used}]" if result.formatter_used else ""
|
|
545
|
+
print(f" {status} {result.file_path} {formatter} {change}")
|
|
546
|
+
if not result.success:
|
|
547
|
+
print(f" → {result.message}")
|
|
548
|
+
|
|
549
|
+
print("-" * 60)
|
|
550
|
+
print(f"Total: {len(results)} | ✅ Success: {success_count} | 🔄 Changed: {changed_count} | ❌ Failed: {failed_count}")
|
|
551
|
+
print("=" * 60)
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def main() -> int:
|
|
555
|
+
parser = argparse.ArgumentParser(
|
|
556
|
+
description="Format code files (Python, TypeScript, JavaScript, Go, Rust, etc.)",
|
|
557
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
558
|
+
epilog="""
|
|
559
|
+
Examples:
|
|
560
|
+
python format_code.py src/app.py # Format single file
|
|
561
|
+
python format_code.py src/app.py src/utils.ts # Format multiple files (parallel)
|
|
562
|
+
python format_code.py --dir src/ # Format directory
|
|
563
|
+
python format_code.py src/app.py --check-only # Check without modifying
|
|
564
|
+
python format_code.py --check-deps # Check formatter dependencies
|
|
565
|
+
python format_code.py src/app.py --json # JSON output for CI/CD
|
|
566
|
+
"""
|
|
567
|
+
)
|
|
568
|
+
parser.add_argument('files', nargs='*', help='Files to format')
|
|
569
|
+
parser.add_argument('--dir', '-d', help='Format all supported files in directory')
|
|
570
|
+
parser.add_argument('--check-only', '-c', action='store_true', help='Check if files need formatting without modifying')
|
|
571
|
+
parser.add_argument('--check-deps', action='store_true', help='Check formatter dependencies')
|
|
572
|
+
parser.add_argument('--json', '-j', action='store_true', help='Output results as JSON')
|
|
573
|
+
parser.add_argument('--verbose', '-v', action='store_true', help='Show detailed output')
|
|
574
|
+
parser.add_argument('--ext', action='append', help='File extensions to format (can specify multiple)')
|
|
575
|
+
parser.add_argument('--workers', '-w', type=int, default=4, help='Number of parallel workers (default: 4)')
|
|
576
|
+
|
|
577
|
+
args = parser.parse_args()
|
|
578
|
+
|
|
579
|
+
formatter = CodeFormatter(verbose=args.verbose, max_workers=args.workers)
|
|
580
|
+
|
|
581
|
+
# Check dependencies mode
|
|
582
|
+
if args.check_deps:
|
|
583
|
+
deps = formatter.check_dependencies()
|
|
584
|
+
if args.json:
|
|
585
|
+
print(json_module.dumps([asdict(d) for d in deps], indent=2))
|
|
586
|
+
else:
|
|
587
|
+
print_dependencies(deps)
|
|
588
|
+
return 0 if all(d.available for d in deps) else 2
|
|
589
|
+
|
|
590
|
+
if not args.files and not args.dir:
|
|
591
|
+
parser.print_help()
|
|
592
|
+
return 1
|
|
593
|
+
|
|
594
|
+
if args.dir:
|
|
595
|
+
results = formatter.format_directory(args.dir, check_only=args.check_only, extensions=args.ext)
|
|
596
|
+
else:
|
|
597
|
+
results = formatter.format_files(args.files, check_only=args.check_only)
|
|
598
|
+
|
|
599
|
+
print_summary(results, json_output=args.json)
|
|
600
|
+
|
|
601
|
+
# Return appropriate exit code
|
|
602
|
+
if all(r.success for r in results):
|
|
603
|
+
return 0
|
|
604
|
+
elif any("not available" in (r.message or "") for r in results):
|
|
605
|
+
return 2
|
|
606
|
+
else:
|
|
607
|
+
return 1
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
if __name__ == "__main__":
|
|
611
|
+
sys.exit(main())
|