summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xdot_local/bin/jflatten.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/dot_local/bin/jflatten.py b/dot_local/bin/jflatten.py
new file mode 100755
index 0000000..bacc754
--- /dev/null
+++ b/dot_local/bin/jflatten.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+
+import argparse
+import json
+import sys
+
+
+def flatten(*path, obj):
+    if isinstance(obj, list):
+        for n, value in enumerate(obj):
+            yield from flatten(*path, n, obj=value)
+    elif isinstance(obj, dict):
+        for key, value in obj.items():
+            yield from flatten(*path, key, obj=value)
+    else:
+        yield path, obj
+
+
+def path_str(*path):
+    return "".join(
+        f"[{part}]" if isinstance(part, int) else f".{part}" for part in path
+    )
+
+
+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("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 = flatten(obj=data)
+    if args.sort_keys:
+        flattened = sorted(flattened)
+    flattened_fmt = ((path_str(*path), value) 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()