mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-04-09 21:04:17 +00:00
for pretty-format-json add option: --empty-object-with-newline
This commit is contained in:
parent
61b5f7e6f7
commit
496e23dea6
4 changed files with 82 additions and 1 deletions
|
|
@ -3,10 +3,15 @@ from __future__ import annotations
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
from difflib import unified_diff
|
from difflib import unified_diff
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
from typing import Sequence
|
from typing import Sequence
|
||||||
|
|
||||||
|
def _insert_linebreaks(json_str) -> str:
|
||||||
|
# (?P<spaces>\s*) seems to capture the \n. Hence, there is no need for it in the substitution string
|
||||||
|
return re.sub(r'\n(?P<spaces>\s*)(?P<json_key>.*): {}(?P<delim>,??)', '\n\g<spaces>\g<json_key>: {\n\g<spaces>}\g<delim>', json_str)
|
||||||
|
|
||||||
def _get_pretty_format(
|
def _get_pretty_format(
|
||||||
contents: str,
|
contents: str,
|
||||||
|
|
@ -14,6 +19,7 @@ def _get_pretty_format(
|
||||||
ensure_ascii: bool = True,
|
ensure_ascii: bool = True,
|
||||||
sort_keys: bool = True,
|
sort_keys: bool = True,
|
||||||
top_keys: Sequence[str] = (),
|
top_keys: Sequence[str] = (),
|
||||||
|
empty_object_with_newline: bool = False,
|
||||||
) -> str:
|
) -> str:
|
||||||
def pairs_first(pairs: Sequence[tuple[str, str]]) -> Mapping[str, str]:
|
def pairs_first(pairs: Sequence[tuple[str, str]]) -> Mapping[str, str]:
|
||||||
before = [pair for pair in pairs if pair[0] in top_keys]
|
before = [pair for pair in pairs if pair[0] in top_keys]
|
||||||
|
|
@ -27,6 +33,8 @@ def _get_pretty_format(
|
||||||
indent=indent,
|
indent=indent,
|
||||||
ensure_ascii=ensure_ascii,
|
ensure_ascii=ensure_ascii,
|
||||||
)
|
)
|
||||||
|
if empty_object_with_newline:
|
||||||
|
json_pretty = _insert_linebreaks(json_pretty)
|
||||||
return f'{json_pretty}\n'
|
return f'{json_pretty}\n'
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -96,6 +104,13 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||||
default=[],
|
default=[],
|
||||||
help='Ordered list of keys to keep at the top of JSON hashes',
|
help='Ordered list of keys to keep at the top of JSON hashes',
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--empty-object-with-newline',
|
||||||
|
action='store_true',
|
||||||
|
dest='empty_object_with_newline',
|
||||||
|
default=False,
|
||||||
|
help='Format empty JSON objects to have a linebreak, also activates --no-sort-keys',
|
||||||
|
)
|
||||||
parser.add_argument('filenames', nargs='*', help='Filenames to fix')
|
parser.add_argument('filenames', nargs='*', help='Filenames to fix')
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
@ -106,9 +121,12 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||||
contents = f.read()
|
contents = f.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if args.empty_object_with_newline:
|
||||||
|
args.no_sort_keys = True
|
||||||
pretty_contents = _get_pretty_format(
|
pretty_contents = _get_pretty_format(
|
||||||
contents, args.indent, ensure_ascii=not args.no_ensure_ascii,
|
contents, args.indent, ensure_ascii=not args.no_ensure_ascii,
|
||||||
sort_keys=not args.no_sort_keys, top_keys=args.top_keys,
|
sort_keys=not args.no_sort_keys, top_keys=args.top_keys,
|
||||||
|
empty_object_with_newline=args.empty_object_with_newline
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print(
|
print(
|
||||||
|
|
@ -118,13 +136,15 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if contents != pretty_contents:
|
if contents != pretty_contents:
|
||||||
|
status = 1
|
||||||
if args.autofix:
|
if args.autofix:
|
||||||
_autofix(json_file, pretty_contents)
|
_autofix(json_file, pretty_contents)
|
||||||
|
if args.empty_object_with_newline:
|
||||||
|
status = 0
|
||||||
else:
|
else:
|
||||||
diff_output = get_diff(contents, pretty_contents, json_file)
|
diff_output = get_diff(contents, pretty_contents, json_file)
|
||||||
sys.stdout.buffer.write(diff_output.encode())
|
sys.stdout.buffer.write(diff_output.encode())
|
||||||
|
|
||||||
status = 1
|
|
||||||
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
|
||||||
17
testing/resources/empty_object_json_multiline.json
Normal file
17
testing/resources/empty_object_json_multiline.json
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"empty": {
|
||||||
|
},
|
||||||
|
"inhabited": {
|
||||||
|
"person": {
|
||||||
|
"name": "Roger",
|
||||||
|
"nested_empty_with_comma": {
|
||||||
|
},
|
||||||
|
"array": [
|
||||||
|
{
|
||||||
|
"nested_empty_in_array": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
testing/resources/empty_object_json_sameline.json
Normal file
14
testing/resources/empty_object_json_sameline.json
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"empty": {},
|
||||||
|
"inhabited": {
|
||||||
|
"person": {
|
||||||
|
"name": "Roger",
|
||||||
|
"nested_empty_with_comma": {},
|
||||||
|
"array": [
|
||||||
|
{
|
||||||
|
"nested_empty_in_array": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import filecmp
|
||||||
|
|
||||||
from pre_commit_hooks.pretty_format_json import main
|
from pre_commit_hooks.pretty_format_json import main
|
||||||
from pre_commit_hooks.pretty_format_json import parse_num_to_int
|
from pre_commit_hooks.pretty_format_json import parse_num_to_int
|
||||||
|
|
@ -137,3 +138,32 @@ def test_diffing_output(capsys):
|
||||||
assert actual_retval == expected_retval
|
assert actual_retval == expected_retval
|
||||||
assert actual_out == expected_out
|
assert actual_out == expected_out
|
||||||
assert actual_err == ''
|
assert actual_err == ''
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty_object_with_newline(tmpdir):
|
||||||
|
# same line objects shoud trigger with --empty-object-with-newline switch
|
||||||
|
sameline = get_resource_path("empty_object_json_sameline.json")
|
||||||
|
ret = main(["--empty-object-with-newline", str(sameline)])
|
||||||
|
assert ret == 1
|
||||||
|
|
||||||
|
multiline = get_resource_path("empty_object_json_multiline.json")
|
||||||
|
to_be_formatted_sameline = tmpdir.join(
|
||||||
|
"not_pretty_formatted_empty_object_json_sameline.json"
|
||||||
|
)
|
||||||
|
shutil.copyfile(str(sameline), str(to_be_formatted_sameline))
|
||||||
|
|
||||||
|
# file has empty object with newline => expect fail with default settings
|
||||||
|
ret = main([str(multiline)])
|
||||||
|
assert ret == 1
|
||||||
|
|
||||||
|
# now launch the autofix with empty object with newline support on that file
|
||||||
|
ret = main(
|
||||||
|
["--autofix", "--empty-object-with-newline", str(to_be_formatted_sameline)]
|
||||||
|
)
|
||||||
|
# it should have formatted it and don't raise an error code
|
||||||
|
assert ret == 0
|
||||||
|
|
||||||
|
# file was formatted (shouldn't trigger linter with --empty-object-with-newline switch)
|
||||||
|
ret = main(["--empty-object-with-newline", str(to_be_formatted_sameline)])
|
||||||
|
assert ret == 0
|
||||||
|
assert filecmp.cmp(to_be_formatted_sameline, multiline)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue