|
5 | 5 | """ |
6 | 6 | import argparse |
7 | 7 | import json |
| 8 | +import re |
8 | 9 | import sys |
| 10 | +from _colorize import ANSIColors, can_colorize |
| 11 | + |
| 12 | + |
| 13 | +# The string we are colorizing is valid JSON, |
| 14 | +# so we can use a looser but simpler regex to match |
| 15 | +# the various parts, most notably strings and numbers, |
| 16 | +# where the regex given by the spec is much more complex. |
| 17 | +_color_pattern = re.compile(r''' |
| 18 | + (?P<key>"(\\.|[^"\\])*")(?=:) | |
| 19 | + (?P<string>"(\\.|[^"\\])*") | |
| 20 | + (?P<boolean>true|false) | |
| 21 | + (?P<null>null) |
| 22 | +''', re.VERBOSE) |
| 23 | + |
| 24 | + |
| 25 | +_colors = { |
| 26 | + 'key': ANSIColors.INTENSE_BLUE, |
| 27 | + 'string': ANSIColors.BOLD_GREEN, |
| 28 | + 'boolean': ANSIColors.BOLD_CYAN, |
| 29 | + 'null': ANSIColors.BOLD_CYAN, |
| 30 | +} |
| 31 | + |
| 32 | + |
| 33 | +def _replace_match_callback(match): |
| 34 | + for key, color in _colors.items(): |
| 35 | + if m := match.group(key): |
| 36 | + return f"{color}{m}{ANSIColors.RESET}" |
| 37 | + return match.group() |
| 38 | + |
| 39 | + |
| 40 | +def _colorize_json(json_str): |
| 41 | + return re.sub(_color_pattern, _replace_match_callback, json_str) |
9 | 42 |
|
10 | 43 |
|
11 | 44 | def main(): |
@@ -68,7 +101,11 @@ def main(): |
68 | 101 | outfile = open(options.outfile, 'w', encoding='utf-8') |
69 | 102 | with outfile: |
70 | 103 | for obj in objs: |
71 | | - json.dump(obj, outfile, **dump_args) |
| 104 | + if can_colorize(file=outfile): |
| 105 | + json_str = json.dumps(obj, **dump_args) |
| 106 | + outfile.write(_colorize_json(json_str)) |
| 107 | + else: |
| 108 | + json.dump(obj, outfile, **dump_args) |
72 | 109 | outfile.write('\n') |
73 | 110 | except ValueError as e: |
74 | 111 | raise SystemExit(e) |
|
0 commit comments