diff --git a/pre_commit_hooks/pretty_format_json.py b/pre_commit_hooks/pretty_format_json.py index 36a90eb..91dae8d 100644 --- a/pre_commit_hooks/pretty_format_json.py +++ b/pre_commit_hooks/pretty_format_json.py @@ -7,13 +7,19 @@ from collections import OrderedDict import simplejson -def _get_pretty_format(contents, indent, sort_keys=True): +def _get_pretty_format(contents, indent, sort_keys=True, top_keys=[]): + def pairs_first(pairs): + before = [pair for pair in pairs if pair[0] in top_keys] + before = sorted(before, key=lambda x: top_keys.index(x[0])) + after = [pair for pair in pairs if pair[0] not in top_keys] + if sort_keys: + after = sorted(after, key=lambda x: x[0]) + return OrderedDict(before + after) return simplejson.dumps( simplejson.loads( contents, - object_pairs_hook=None if sort_keys else OrderedDict, + object_pairs_hook=pairs_first, ), - sort_keys=sort_keys, indent=indent ) + "\n" # dumps don't end with a newline @@ -44,6 +50,11 @@ def parse_indent(s): ) +def parse_topkeys(s): + # type: (str) -> array + return s.split(',') + + def pretty_format_json(argv=None): parser = argparse.ArgumentParser() parser.add_argument( @@ -65,6 +76,13 @@ def pretty_format_json(argv=None): default=False, help='Keep JSON nodes in the same order', ) + parser.add_argument( + '--top-keys', + type=parse_topkeys, + dest='top_keys', + default=[], + help='Ordered list of keys to keep at the top of JSON hashes', + ) parser.add_argument('filenames', nargs='*', help='Filenames to fix') args = parser.parse_args(argv) @@ -78,6 +96,7 @@ def pretty_format_json(argv=None): try: pretty_contents = _get_pretty_format( contents, args.indent, sort_keys=not args.no_sort_keys, + top_keys=args.top_keys ) if contents != pretty_contents: diff --git a/testing/resources/top_sorted_json.json b/testing/resources/top_sorted_json.json new file mode 100644 index 0000000..62083e7 --- /dev/null +++ b/testing/resources/top_sorted_json.json @@ -0,0 +1,16 @@ +{ + "01-alist": [ + 2, + 34, + 234 + ], + "alist": [ + 2, + 34, + 234 + ], + "00-foo": "bar", + "02-blah": null, + "blah": null, + "foo": "bar" +} diff --git a/tests/pretty_format_json_test.py b/tests/pretty_format_json_test.py index d9061d3..7bfc31f 100644 --- a/tests/pretty_format_json_test.py +++ b/tests/pretty_format_json_test.py @@ -65,6 +65,21 @@ def test_autofix_pretty_format_json(tmpdir): assert ret == 0 +def test_orderfile_get_pretty_format(): + ret = pretty_format_json(['--top-keys=alist', get_resource_path('pretty_formatted_json.json')]) + assert ret == 0 + + +def test_not_orderfile_get_pretty_format(): + ret = pretty_format_json(['--top-keys=blah', get_resource_path('pretty_formatted_json.json')]) + assert ret == 1 + + +def test_top_sorted_get_pretty_format(): + ret = pretty_format_json(['--top-keys=01-alist,alist', get_resource_path('top_sorted_json.json')]) + assert ret == 0 + + def test_badfile_pretty_format_json(): ret = pretty_format_json([get_resource_path('ok_yaml.yaml')]) assert ret == 1