85 lines
2.6 KiB
Python
85 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
JSON Validator and Formatter Utility
|
|
|
|
Validates and pretty-prints JSON files with customizable indentation.
|
|
Supports file input or stdin piping.
|
|
|
|
Usage:
|
|
json_formatter.py <input.json> [indent] # format file
|
|
echo '{}' | json_formatter.py # format from stdin
|
|
json_formatter.py invalid.json # validate (exit code 3 if invalid)
|
|
|
|
Exit codes:
|
|
0 - Valid JSON, output printed to stdout
|
|
1 - No input provided (stdin mode)
|
|
2 - File not found
|
|
3 - Invalid JSON syntax
|
|
4 - Other error
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def format_json(input_path: str = None, content: str = None, indent: int = 2) -> str:
|
|
"""
|
|
Read JSON from file or string, validate it, and return formatted output.
|
|
|
|
Args:
|
|
input_path: Path to the JSON file (mutually exclusive with content)
|
|
content: Raw JSON string content (mutually exclusive with input_path)
|
|
indent: Number of spaces for indentation (default: 2)
|
|
|
|
Returns:
|
|
Formatted JSON string
|
|
|
|
Raises:
|
|
FileNotFoundError: If file doesn't exist
|
|
json.JSONDecodeError: If file contains invalid JSON
|
|
"""
|
|
if content is None:
|
|
path = Path(input_path)
|
|
if not path.exists():
|
|
raise FileNotFoundError(f"File not found: {input_path}")
|
|
with open(path, 'r', encoding='utf-8') as f:
|
|
data = json.load(f)
|
|
else:
|
|
data = json.loads(content)
|
|
|
|
# Validate by re-serializing
|
|
json.dumps(data) # Will raise if data contains non-serializable types
|
|
|
|
return json.dumps(data, indent=indent, ensure_ascii=False, sort_keys=True)
|
|
|
|
|
|
def main():
|
|
input_file = sys.argv[1] if len(sys.argv) > 1 else None
|
|
indent = int(sys.argv[2]) if len(sys.argv) > 2 else 2
|
|
|
|
try:
|
|
if input_file:
|
|
formatted = format_json(input_path=input_file, indent=indent)
|
|
else:
|
|
# Read from stdin
|
|
content = sys.stdin.read()
|
|
if not content.strip():
|
|
print("Error: No input provided", file=sys.stderr)
|
|
sys.exit(1)
|
|
formatted = format_json(content=content, indent=indent)
|
|
print(formatted)
|
|
sys.exit(0)
|
|
except FileNotFoundError as e:
|
|
print(f"Error: {e}", file=sys.stderr)
|
|
sys.exit(2)
|
|
except json.JSONDecodeError as e:
|
|
print(f"JSON Error: {e.msg} at line {e.lineno}, column {e.colno}", file=sys.stderr)
|
|
sys.exit(3)
|
|
except Exception as e:
|
|
print(f"Unexpected error: {e}", file=sys.stderr)
|
|
sys.exit(4)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |