diff options
Diffstat (limited to 'dot_local/bin/executable_jflatten.py')
-rw-r--r-- | dot_local/bin/executable_jflatten.py | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/dot_local/bin/executable_jflatten.py b/dot_local/bin/executable_jflatten.py new file mode 100644 index 0000000..99849dc --- /dev/null +++ b/dot_local/bin/executable_jflatten.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 + +import argparse +import decimal +import json +import sys + +GREEN = "\033[1;32m" +GREY = "\033[0;37m" +CLEAR = "\033[0m" +RED = "\033[1;31m" +YELLOW = "\033[1;33m" +BLUE = "\033[1;34m" +MAGENTA = "\033[1;35m" + + +def flatten(*path, obj): + if isinstance(obj, list): + yield path, obj + for n, value in enumerate(obj): + yield from flatten(*path, n, obj=value) + elif isinstance(obj, dict): + yield path, obj + for key, value in obj.items(): + yield from flatten(*path, key, obj=value) + else: + yield path, obj + + +def fmt_path(*path, colour): + parts = [] + if not colour: + for part in path: + parts.append(f"[{part}]" if isinstance(part, int) else f".{part}") + else: + for part in path: + if isinstance(part, int): + parts.append(f"{GREY}[{BLUE}{part}{GREY}]{CLEAR}") + else: + parts.append(f"{GREY}.{MAGENTA}{part}{CLEAR}") + return "".join(parts) + + +def fmt_value(value, colour): + if not colour: + return { + None: "null", + True: "true", + False: "false", + }.get(value, str(value)) + if value is None: + return f"{GREY}null{CLEAR}" + if value is True: + return f"{GREEN}true{CLEAR}" + if value is False: + return f"{RED}false{CLEAR}" + if isinstance(value, str): + return f"{YELLOW}{value}{CLEAR}" + if isinstance(value, (int, float, decimal.Decimal)): + return f"{BLUE}{value}{CLEAR}" + return str(value) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--sort-keys", "-s", action="store_true") + parser.add_argument("--json", "-j", action="store_true") + parser.add_argument("--show-empty-collections", action="store_true") + parser.add_argument("--colour", "-c", action="store_true") + parser.add_argument("--no-colour", "-C", action="store_true") + parser.add_argument("file", nargs="?") + args = parser.parse_args() + + if args.file: + with open(args.file) as f: + data = json.load(f) + else: + data = json.load(sys.stdin) + + flattened = ( + (path, value) + for path, value in flatten(obj=data) + if not isinstance(value, (dict, list)) + or not value + and args.show_empty_collections + ) + + if args.json: + print( + json.dumps( + {fmt_path(*path, colour=False): value for path, value in flattened}, + indent=True, + sort_keys=args.sort_keys, + ), + ) + return + + if args.sort_keys: + flattened = sorted(flattened) + colour = not args.no_colour and (args.colour or sys.stdout.isatty()) + flattened_fmt = ( + (fmt_path(*path, colour=colour), fmt_value(value, colour=colour)) + for path, value in flattened + ) + + if args.json: + print(json.dumps(dict(flattened_fmt), indent=True)) + else: + print("\n".join(f"{path}:{value}" for path, value in flattened_fmt)) + + +if __name__ == "__main__": + main() |