blob: afbe696cab7387730cda1e793cdb1df66976d098 [file] [log] [blame]
James Feist3cb5fec2018-01-23 14:41:51 -08001#!/usr/bin/python3
2# all arguments to this script are considered as json files
3# and attempted to be formatted alphabetically
4
5import json
James Feist5ffd8b42019-10-25 11:22:10 -07006import os
Potin Lai0f3a4d92023-12-05 00:13:55 +08007import re
James Feist3cb5fec2018-01-23 14:41:51 -08008from sys import argv
Potin Lai0f3a4d92023-12-05 00:13:55 +08009from typing import List, Tuple, Union
10
11# Trying to parse JSON comments and then being able to re-insert them into
12# the correct location on a re-emitted and sorted JSON would be very difficult.
13# To make this somewhat manageable, we take a few shortcuts here:
14#
15# - Single-line style comments (//) can be on a new line or at the end of
16# a line with contents.
17#
18# - Multi-line style comments (/* */) use the must be free-standing.
19#
20# - Comments will get inserted back into the file in the line they came
21# from. If keys are resorted or the number of lines change, all bets
22# for correctness are off.
23#
24# - No attempts to re-indent multi-line comments will be made.
25#
26# In light of this, it is highly recommended to use a JSON formatter such as
27# prettier before using this script and planning to move multi-line comments
28# around after key resorting.
29
30
31class CommentTracker:
32 # Regex patterns used.
33 single_line_pattern = re.compile(r"\s*//.*$")
34 multi_line_start_pattern = re.compile(r"/\*")
35 multi_line_end_pattern = re.compile(r".*\*/", re.MULTILINE | re.DOTALL)
36
37 def __init__(self) -> None:
38 self.comments: List[Tuple[bool, int, str]] = []
39
40 # Extract out the comments from a JSON-like string and save them away.
41 def extract_comments(self, contents: str) -> str:
42 result = []
43
44 multi_line_segment: Union[str, None] = None
45 multi_line_start = 0
46
47 for idx, line in enumerate(contents.split("\n")):
48 single = CommentTracker.single_line_pattern.search(line)
49 if single:
50 do_append = False if line.startswith(single.group(0)) else True
51 line = line[: single.start(0)]
52 self.comments.append((do_append, idx, single.group(0)))
53
54 multi_start = CommentTracker.multi_line_start_pattern.search(line)
55 if not multi_line_segment and multi_start:
56 multi_line_start = idx
57 multi_line_segment = line
58 elif multi_line_segment:
59 multi_line_segment = multi_line_segment + "\n" + line
60
61 if not multi_line_segment:
62 result.append(line)
63 continue
64
65 multi_end = CommentTracker.multi_line_end_pattern.search(
66 multi_line_segment
67 )
68 if multi_end:
69 self.comments.append(
70 (False, multi_line_start, multi_end.group(0))
71 )
72 result.append(multi_line_segment[multi_end.end(0) :])
73 multi_line_segment = None
74
75 return "\n".join(result)
76
77 # Re-insert the saved off comments into a JSON-like string.
78 def insert_comments(self, contents: str) -> str:
79 result = contents.split("\n")
80
81 for append, idx, string in self.comments:
82 if append:
83 result[idx] = result[idx] + string
84 else:
85 result = result[:idx] + string.split("\n") + result[idx:]
86
87 return "\n".join(result)
88
James Feist3cb5fec2018-01-23 14:41:51 -080089
James Feist5ffd8b42019-10-25 11:22:10 -070090files = argv[1:]
91
92for file in files[:]:
93 if os.path.isdir(file):
94 files.remove(file)
95 for f in os.listdir(file):
96 files.append(os.path.join(file, f))
97
98for file in files:
Patrick Williamscad2d1f2022-12-04 14:38:16 -060099 if not file.endswith(".json"):
Brad Bishopca000e52019-12-19 15:43:06 -0500100 continue
James Feistc4e56942019-04-19 12:15:19 -0700101 print("formatting file {}".format(file))
Potin Lai0f3a4d92023-12-05 00:13:55 +0800102
103 comments = CommentTracker()
104
105 with open(file) as fp:
106 j = json.loads(comments.extract_comments(fp.read()))
James Feist3cb5fec2018-01-23 14:41:51 -0800107
James Feistc4e56942019-04-19 12:15:19 -0700108 if isinstance(j, list):
109 for item in j:
110 item["Exposes"] = sorted(item["Exposes"], key=lambda k: k["Type"])
111 else:
112 j["Exposes"] = sorted(j["Exposes"], key=lambda k: k["Type"])
113
Potin Lai0f3a4d92023-12-05 00:13:55 +0800114 with open(file, "w") as fp:
115 contents = json.dumps(
116 j, indent=4, sort_keys=True, separators=(",", ": ")
Patrick Williamscad2d1f2022-12-04 14:38:16 -0600117 )
Potin Lai0f3a4d92023-12-05 00:13:55 +0800118
119 fp.write(comments.insert_comments(contents))
120 fp.write("\n")