--- /dev/null
+#!/usr/bin/env python3
+#
+# Script to sort or just check that properties are in alphabetic order
+
+
+import json
+import sys
+import argparse
+from collections import OrderedDict
+
+
+def sort_properties(obj, path=""):
+ """Recursively sort 'properties' keys in a JSON schema object."""
+ if isinstance(obj, dict):
+ new_obj = OrderedDict()
+
+ for key, value in obj.items():
+ current_path = f"{path}.{key}" if path else key
+
+ if key == "properties" and isinstance(value, dict):
+ sorted_properties = OrderedDict(sorted(value.items()))
+ new_obj[key] = sorted_properties
+ for prop_key, prop_value in sorted_properties.items():
+ new_obj[key][prop_key] = sort_properties(
+ prop_value, f"{current_path}.{prop_key}"
+ )
+ else:
+ new_obj[key] = sort_properties(value, current_path)
+
+ return new_obj
+
+ elif isinstance(obj, list):
+ return [sort_properties(item, f"{path}[{i}]") for i, item in enumerate(obj)]
+
+ else:
+ return obj
+
+
+def check_properties_sorted(obj, path=""):
+ """Check if all 'properties' keys have their contents sorted alphabetically."""
+ errors = []
+
+ if isinstance(obj, dict):
+ for key, value in obj.items():
+ current_path = f"{path}.{key}" if path else key
+ if key == "properties" and isinstance(value, dict):
+ keys_list = list(value.keys())
+ sorted_keys = sorted(keys_list)
+
+ if keys_list != sorted_keys:
+ errors.append(f"Properties not sorted at path: {current_path}")
+ errors.append(f" Current order: {keys_list}")
+ errors.append(f" Should be: {sorted_keys}")
+
+ for prop_key, prop_value in value.items():
+ errors.extend(
+ check_properties_sorted(
+ prop_value, f"{current_path}.{prop_key}"
+ )
+ )
+ else:
+ errors.extend(check_properties_sorted(value, current_path))
+
+ elif isinstance(obj, list):
+ for i, item in enumerate(obj):
+ errors.extend(check_properties_sorted(item, f"{path}[{i}]"))
+
+ return errors
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Sort JSON schema properties alphabetically"
+ )
+ parser.add_argument("schema_file", help="Path to the JSON schema file")
+ parser.add_argument(
+ "--check",
+ action="store_true",
+ help="Check if properties are sorted (exit 1 if not)",
+ )
+ parser.add_argument(
+ "--in-place",
+ action="store_true",
+ help="Sort the file in place (only if not in check mode)",
+ )
+
+ args = parser.parse_args()
+
+ try:
+ with open(args.schema_file, "r") as f:
+ schema = json.load(f, object_pairs_hook=OrderedDict)
+ except Exception as e:
+ print(f"Error reading schema file: {e}", file=sys.stderr)
+ sys.exit(1)
+
+ if args.check:
+ errors = check_properties_sorted(schema)
+
+ if errors:
+ print("Schema properties are not sorted!", file=sys.stderr)
+ for error in errors:
+ print(error, file=sys.stderr)
+ sys.exit(1)
+ else:
+ print("Schema properties are properly sorted.")
+ sys.exit(0)
+ else:
+ sorted_schema = sort_properties(schema)
+
+ if args.in_place:
+ try:
+ with open(args.schema_file, "w") as f:
+ json.dump(sorted_schema, f, indent=4)
+ f.write("\n")
+ print(f"Sorted schema written to {args.schema_file}")
+ except Exception as e:
+ print(f"Error writing schema file: {e}", file=sys.stderr)
+ sys.exit(1)
+ else:
+ print(json.dumps(sorted_schema, indent=4))
+
+
+if __name__ == "__main__":
+ main()