| 24 | from collections import OrderedDict |
| 25 | |
| 26 | def main(): |
| 27 | parser = argparse.ArgumentParser(description="Beautify JSON files with consistent formatting.") |
| 28 | parser.add_argument('json_files', nargs='+', help='One or more JSON files to beautify') |
| 29 | parser.add_argument('-v', '--verbose', action='count', default=0, help='Increase output verbosity (can use -vv)') |
| 30 | parser.add_argument('-q', '--quiet', action='store_true', help='Suppress non-error output') |
| 31 | parser.add_argument('--indent', type=int, default=2, help='Number of spaces for indentation (default: 2)') |
| 32 | parser.add_argument('--stop-on-error', action='store_true', help='Stop on the first error encountered') |
| 33 | args = parser.parse_args() |
| 34 | |
| 35 | # Set up the logging level |
| 36 | if args.quiet: |
| 37 | loglevel = logging.ERROR |
| 38 | elif args.verbose >= 2: |
| 39 | loglevel = logging.DEBUG |
| 40 | elif args.verbose == 1: |
| 41 | loglevel = logging.INFO |
| 42 | else: |
| 43 | loglevel = logging.WARNING |
| 44 | logging.basicConfig(level=loglevel, format='%(levelname)s: %(message)s') |
| 45 | |
| 46 | # Process each JSON file |
| 47 | all_success = True |
| 48 | for json_file in args.json_files: |
| 49 | if not os.path.isfile(json_file): |
| 50 | logging.error(f"JSON file '{json_file}' does not exist.") |
| 51 | all_success = False |
| 52 | if args.stop_on_error: |
| 53 | sys.exit(1) |
| 54 | continue |
| 55 | |
| 56 | try: |
| 57 | # Load JSON with OrderedDict to preserve key order |
| 58 | logging.info(f"Processing '{json_file}'") |
| 59 | with open(json_file, 'r', encoding='utf-8') as fp: |
| 60 | json_data = json.load(fp, object_pairs_hook=OrderedDict) |
| 61 | |
| 62 | # Write beautified JSON back to the file |
| 63 | with open(json_file, 'w', encoding='utf-8') as fp: |
| 64 | json.dump(json_data, fp, indent=args.indent, separators=(",", ": "), ensure_ascii=False) |
| 65 | # Add a final newline |
| 66 | print("", file=fp) |
| 67 | |
| 68 | logging.info(f"Successfully beautified '{json_file}'") |
| 69 | |
| 70 | except json.JSONDecodeError as e: |
| 71 | logging.error(f"Invalid JSON in '{json_file}': {e}") |
| 72 | all_success = False |
| 73 | if args.stop_on_error: |
| 74 | sys.exit(1) |
| 75 | except Exception as e: |
| 76 | logging.error(f"Error processing '{json_file}': {e}") |
| 77 | all_success = False |
| 78 | if args.stop_on_error: |
| 79 | sys.exit(1) |
| 80 | |
| 81 | if not all_success: |
| 82 | sys.exit(1) |
| 83 | |