Skip to content

Commit 98885ee

Browse files
pfeerickclaude
andcommitted
fix(tools): sort tags/categories case-insensitively
Plain sorted() put 'GPS & Mapping' before 'Games & Fun' (uppercase 'P' < lowercase 'a' in ASCII) — not the order a human reading the dropdown would expect. Also fixes a related bug the case-insensitive change would otherwise introduce: the schema-vs-current comparisons re-sorted both sides before comparing, which hid ordering drift in scripts.schema.json's own examples arrays (they're supposed to already hold the canonical sorted list, so a stale on-disk order needs to be caught, not normalized away). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 9266449 commit 98885ee

4 files changed

Lines changed: 39 additions & 19 deletions

File tree

.github/ISSUE_TEMPLATE/add-script.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ body:
3232
# --- BEGIN AUTO-GENERATED CATEGORIES (see scripts.schema.json: items.properties.category.examples) ---
3333
- Audio & Media
3434
- Flight Controller Config
35-
- GPS & Mapping
3635
- Games & Fun
36+
- GPS & Mapping
3737
- Logging & Analysis
3838
- Radio Tools
3939
- Telemetry & Widgets

.github/ISSUE_TEMPLATE/update-script.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ body:
3030
# --- BEGIN AUTO-GENERATED CATEGORIES (see scripts.schema.json: items.properties.category.examples) ---
3131
- Audio & Media
3232
- Flight Controller Config
33-
- GPS & Mapping
3433
- Games & Fun
34+
- GPS & Mapping
3535
- Logging & Analysis
3636
- Radio Tools
3737
- Telemetry & Widgets

scripts.schema.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@
66
"items": {
77
"type": "object",
88
"title": "ScriptEntry",
9-
"required": ["name", "category", "description", "infourl", "tags"],
9+
"required": [
10+
"name",
11+
"category",
12+
"description",
13+
"infourl",
14+
"tags"
15+
],
1016
"properties": {
1117
"name": {
1218
"type": "string",
@@ -20,8 +26,8 @@
2026
"examples": [
2127
"Audio & Media",
2228
"Flight Controller Config",
23-
"GPS & Mapping",
2429
"Games & Fun",
30+
"GPS & Mapping",
2531
"Logging & Analysis",
2632
"Radio Tools",
2733
"Telemetry & Widgets"
@@ -39,7 +45,9 @@
3945
},
4046
"images": {
4147
"type": "array",
42-
"items": { "type": "string" },
48+
"items": {
49+
"type": "string"
50+
},
4351
"description": "Screenshot references: local ASSETS/ paths or external image URLs."
4452
},
4553
"tags": {

tools/sync_issue_template_options.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,24 @@ def save_schema(path: Path, schema: dict) -> None:
112112

113113
# ── Computation ──────────────────────────────────────────────────────────────
114114

115+
def _sort(values) -> list[str]:
116+
"""Case-insensitive sort — plain sorted() would put e.g. 'GPS & Mapping'
117+
before 'Games & Fun' (uppercase 'P' < lowercase 'a' in ASCII), which
118+
isn't the order a human reading the dropdown/checkbox list would expect."""
119+
return sorted(values, key=str.casefold)
120+
121+
115122
def compute(scripts: list, schema: dict) -> dict:
116-
current_tags = sorted({tag for e in scripts for tag in e.get("tags", []) if isinstance(tag, str)})
123+
current_tags = _sort({tag for e in scripts for tag in e.get("tags", []) if isinstance(tag, str)})
117124

118-
used_categories = sorted({
125+
used_categories = _sort({
119126
e["category"] for e in scripts
120127
if isinstance(e.get("category"), str) and e["category"].strip()
121128
})
122129
previous_categories = get_schema_examples(schema, "category")
123-
current_categories = sorted(set(previous_categories) | set(used_categories))
124-
new_categories = sorted(set(used_categories) - set(previous_categories))
125-
unused_categories = sorted(set(current_categories) - set(used_categories))
130+
current_categories = _sort(set(previous_categories) | set(used_categories))
131+
new_categories = _sort(set(used_categories) - set(previous_categories))
132+
unused_categories = _sort(set(current_categories) - set(used_categories))
126133

127134
return {
128135
"current_tags": current_tags,
@@ -219,8 +226,8 @@ def check_template(template_path: Path, current_tags: list[str], current_categor
219226
expected_values = current_tags if block_name == "tags" else current_categories
220227
if actual == expected_values:
221228
continue
222-
missing = sorted(set(expected_values) - set(actual))
223-
extra = sorted(set(actual) - set(expected_values))
229+
missing = _sort(set(expected_values) - set(actual))
230+
extra = _sort(set(actual) - set(expected_values))
224231
diff = "\n".join(
225232
difflib.unified_diff(
226233
lines[begin_idx:end_idx + 1],
@@ -277,19 +284,24 @@ def main() -> None:
277284
if args.check:
278285
issues = []
279286

287+
# Direct (order-sensitive) comparison, not sorted() on both sides —
288+
# the schema's examples arrays are always supposed to already hold
289+
# the canonical _sort()-ordered list, so a stale *order* on disk
290+
# (e.g. written before a sort-key change) must count as drift too,
291+
# not just a stale *set* of values.
280292
schema_tags = get_schema_examples(schema, "tags")
281-
if sorted(schema_tags) != current_tags:
293+
if schema_tags != current_tags:
282294
issues.append(
283295
f"{args.schema} [tags.examples]: out of sync\n"
284-
f" missing: {sorted(set(current_tags) - set(schema_tags))}\n"
285-
f" extra: {sorted(set(schema_tags) - set(current_tags))}"
296+
f" missing: {_sort(set(current_tags) - set(schema_tags))}\n"
297+
f" extra: {_sort(set(schema_tags) - set(current_tags))}"
286298
)
287299
schema_categories = get_schema_examples(schema, "category")
288-
if sorted(schema_categories) != current_categories:
300+
if schema_categories != current_categories:
289301
issues.append(
290302
f"{args.schema} [category.examples]: out of sync\n"
291-
f" missing: {sorted(set(current_categories) - set(schema_categories))}\n"
292-
f" extra: {sorted(set(schema_categories) - set(current_categories))}"
303+
f" missing: {_sort(set(current_categories) - set(schema_categories))}\n"
304+
f" extra: {_sort(set(schema_categories) - set(current_categories))}"
293305
)
294306

295307
for template_path in args.templates:
@@ -310,7 +322,7 @@ def main() -> None:
310322

311323
schema_tags = get_schema_examples(schema, "tags")
312324
schema_categories = get_schema_examples(schema, "category")
313-
if sorted(schema_tags) != current_tags or sorted(schema_categories) != current_categories:
325+
if schema_tags != current_tags or schema_categories != current_categories:
314326
set_schema_examples(schema, "tags", current_tags)
315327
set_schema_examples(schema, "category", current_categories)
316328
save_schema(args.schema, schema)

0 commit comments

Comments
 (0)