55import datetime as dt
66import json
77import sys
8+ from collections .abc import Callable
89from pathlib import Path
910from typing import Any
1011from urllib .parse import urlparse
@@ -164,6 +165,32 @@ def chronological_key(p: Post) -> float:
164165 sys .stdout .write ("\n " )
165166
166167
168+ def _dump_grouped_items (
169+ posts : list [Post ],
170+ grouping_fn : Callable [[list [Post ]], dict [str , tuple [str , list [Post ]]]],
171+ ) -> None :
172+ """Dump grouped post attributes to stdout as a JSON structure.
173+
174+ Args:
175+ posts: The list of posts to process.
176+ grouping_fn: A function that groups posts by the desired attribute.
177+ """
178+ from blogmore .parser import sanitize_for_url
179+
180+ grouped = grouping_fn (posts )
181+
182+ pairs : list [tuple [str , str ]] = []
183+ for lower_key , (display_name , _ ) in grouped .items ():
184+ slug = sanitize_for_url (lower_key )
185+ pairs .append ((slug , display_name ))
186+
187+ # Sort case-insensitively by display name
188+ pairs .sort (key = lambda pair : pair [1 ].lower ())
189+
190+ json .dump (pairs , sys .stdout , indent = 2 )
191+ sys .stdout .write ("\n " )
192+
193+
167194def dump_categories (posts : list [Post ]) -> None :
168195 """Dump all categories found in posts to stdout as a JSON structure.
169196
@@ -176,20 +203,8 @@ def dump_categories(posts: list[Post]) -> None:
176203 posts: The list of posts to process.
177204 """
178205 from blogmore .generator .grouping import group_posts_by_category
179- from blogmore .parser import sanitize_for_url
180-
181- posts_by_category = group_posts_by_category (posts )
182206
183- category_pairs : list [tuple [str , str ]] = []
184- for category_lower , (category_display , _ ) in posts_by_category .items ():
185- slug = sanitize_for_url (category_lower )
186- category_pairs .append ((slug , category_display ))
187-
188- # Sort case-insensitively by display name to match the category cloud page
189- category_pairs .sort (key = lambda pair : pair [1 ].lower ())
190-
191- json .dump (category_pairs , sys .stdout , indent = 2 )
192- sys .stdout .write ("\n " )
207+ _dump_grouped_items (posts , group_posts_by_category )
193208
194209
195210def dump_tags (posts : list [Post ]) -> None :
@@ -204,20 +219,8 @@ def dump_tags(posts: list[Post]) -> None:
204219 posts: The list of posts to process.
205220 """
206221 from blogmore .generator .grouping import group_posts_by_tag
207- from blogmore .parser import sanitize_for_url
208222
209- posts_by_tag = group_posts_by_tag (posts )
210-
211- tag_pairs : list [tuple [str , str ]] = []
212- for tag_lower , (tag_display , _ ) in posts_by_tag .items ():
213- slug = sanitize_for_url (tag_lower )
214- tag_pairs .append ((slug , tag_display ))
215-
216- # Sort case-insensitively by display name to match the tag cloud page
217- tag_pairs .sort (key = lambda pair : pair [1 ].lower ())
218-
219- json .dump (tag_pairs , sys .stdout , indent = 2 )
220- sys .stdout .write ("\n " )
223+ _dump_grouped_items (posts , group_posts_by_tag )
221224
222225
223226def dump_series (posts : list [Post ]) -> None :
@@ -232,17 +235,5 @@ def dump_series(posts: list[Post]) -> None:
232235 posts: The list of posts to process.
233236 """
234237 from blogmore .generator .grouping import group_posts_by_series
235- from blogmore .parser import sanitize_for_url
236-
237- posts_by_series = group_posts_by_series (posts )
238238
239- series_pairs : list [tuple [str , str ]] = []
240- for series_lower , (series_display , _ ) in posts_by_series .items ():
241- slug = sanitize_for_url (series_lower )
242- series_pairs .append ((slug , series_display ))
243-
244- # Sort case-insensitively by display name to match the series index page
245- series_pairs .sort (key = lambda pair : pair [1 ].lower ())
246-
247- json .dump (series_pairs , sys .stdout , indent = 2 )
248- sys .stdout .write ("\n " )
239+ _dump_grouped_items (posts , group_posts_by_series )
0 commit comments