fix: site systems match under every spelling

Platform pages matched emulators to systems by the exact id, so the RetroArch page listed none for sega-mega-drive (genesis_plus_gx says sega-megadrive), and listed every emulator of a system instead of those the platform runs. Emulator cards linked only ids a platform uses: 2,057 of 4,215 system lines had no link, now 327, the rest having no page. Ids are compared as _norm_system_id reads them, and a system only profiles name is placed by the files they file under it.
This commit is contained in:
Abdessamad Derraz committed 2026-10-20 04:55:16 +02:00
1 parent 2e0d3d626a
commit 91403aa149
3 files changed
+119 -16

No files matched your search

+50 -14
View File
@@ -146,6 +146,7 @@ def _build_system_page_map_from_data(
manufacturers: dict,
coverages: dict,
db: dict,
profiles: dict | None = None,
) -> None:
"""Build system_id -> (manufacturer_slug, console_name) mapping.
@@ -210,6 +211,26 @@ def _build_system_page_map_from_data(
_system_page_map[sys_id] = console_norm[suffix]
break
# Systems only emulator profiles name (sega-naomi, commodore-pet): placed
# by the files the profile files under them, as a platform's are. A
# profile of one system files all of its entries there.
for profile in (profiles or {}).values():
systems = [str(sid) for sid in profile.get("systems") or []]
for sys_id in systems:
if sys_id in _system_page_map:
continue
files = [
entry for entry in profile.get("files") or []
if isinstance(entry, dict)
and (entry.get("system") == sys_id or len(systems) == 1)
]
place = _system_folder(files, db, name_consoles)
if place is not None:
mfr, console = place
_system_page_map[sys_id] = (mfr.lower().replace(" ", "-"), console)
elif sys_id in console_norm:
_system_page_map[sys_id] = console_norm[sys_id]
@@ -1680,11 +1701,7 @@ def _render_platform_systems(
ok_count = sum(1 for f in files if f["status"] == "ok")
total = len(files)
sys_emus = []
if emulator_files:
for emu_name, emu_data in emulator_files.items():
if sys_id in emu_data.get("systems", set()):
sys_emus.append(emu_name)
sys_emus = _system_emulators(sys_id, emulator_files)
sys_link = _system_link(sys_id, "../")
@@ -1914,11 +1931,7 @@ def generate_platform_page(
f'<span class="rb-badge rb-badge-warning">'
f'{non_ok} issue{"s" if non_ok > 1 else ""}</span>'
)
sys_emus = []
if emulator_files:
for emu_name, emu_data in emulator_files.items():
if sys_id in emu_data.get("systems", set()):
sys_emus.append(emu_name)
sys_emus = _system_emulators(sys_id, emulator_files)
emu_str = ", ".join(sys_emus[:3])
if len(sys_emus) > 3:
emu_str += f" +{len(sys_emus) - 3}"
@@ -4108,14 +4121,33 @@ def _build_file_consumers(db: dict, coverages: dict, profiles: dict) -> FileCons
def _build_emulator_file_index(profiles: dict) -> dict[str, dict]:
"""Map emulator_name -> {systems: set}, for the platform pages."""
"""Map emulator_name -> {systems, norm}, for the platform pages.
norm holds the systems as _norm_system_id reads them: a platform files
the Mega Drive as sega-mega-drive and genesis_plus_gx as sega-megadrive,
and an exact match left the RetroArch page with no emulator for it.
"""
from common import _norm_system_id
return {
name: {"systems": set(profile.get("systems", []))}
name: {
"systems": set(profile.get("systems", [])),
"norm": {_norm_system_id(str(s)) for s in profile.get("systems", [])},
}
for name, profile in profiles.items()
if profile.get("type") != "alias"
}
def _system_emulators(sys_id: str, emulator_files: dict | None) -> list[str]:
"""The emulators a platform runs for one of its systems."""
from common import _norm_system_id
norm = _norm_system_id(sys_id)
return [name for name, data in (emulator_files or {}).items()
if sys_id in data["systems"] or norm in data["norm"]]
def _mkdocs_config(docs: Path, text: str) -> tuple[Path, str]:
"""Where the site's config goes, and its text for that place.
@@ -4533,7 +4565,7 @@ def _generate(args: argparse.Namespace) -> None:
# Build system_id -> manufacturer page map (needed by all generators)
print("Building system cross-reference map...")
manufacturers = _group_by_manufacturer(db)
_build_system_page_map_from_data(manufacturers, coverages, db)
_build_system_page_map_from_data(manufacturers, coverages, db, profiles)
print(f" {len(_system_page_map)} system IDs mapped to pages")
# Generate platform pages
@@ -4543,9 +4575,13 @@ def _generate(args: argparse.Namespace) -> None:
generate_platform_index(coverages, registry),
)
for name, cov in coverages.items():
# The emulators this platform runs, not every one of the system.
runs = resolve_platform_cores(cov["config"], profiles)
write_if_changed(
str(docs / "platforms" / f"{name}.md"),
generate_platform_page(name, cov, registry, emulator_files),
generate_platform_page(name, cov, registry, {
emu: data for emu, data in emulator_files.items() if emu in runs
}),
)
PAGE_DATA[f"platforms/{name}.md"] = platform_structured_data(name, cov)
+29 -2
View File
@@ -128,10 +128,37 @@ def _slugify_anchor(text: str) -> str:
slug = slug.strip("-")
return slug
_norm_page_cache: dict[str, tuple[str, str] | None] = {}
_norm_page_size = -1
def _page_by_norm(sys_id: str) -> tuple[str, str] | None:
"""The page an id leads to under another spelling of the same system.
Emulator cards name sega-megadrive or sinclair-zxspectrum, the pages are
keyed by the platforms' spellings: 2,431 of 4,195 cards had no link. A
spelling two pages share leads nowhere rather than to either.
"""
global _norm_page_size
from common import _norm_system_id
if _norm_page_size != len(_system_page_map):
_norm_page_cache.clear()
for known, page in _system_page_map.items():
key = _norm_system_id(known)
if _norm_page_cache.get(key, page) != page:
_norm_page_cache[key] = None
else:
_norm_page_cache[key] = page
_norm_page_size = len(_system_page_map)
return _norm_page_cache.get(_norm_system_id(sys_id))
def _system_link(sys_id: str, prefix: str = "") -> str:
"""Generate a markdown link to a system page with anchor."""
if sys_id in _system_page_map:
slug, console = _system_page_map[sys_id]
page = _system_page_map.get(sys_id) or _page_by_norm(sys_id)
if page:
slug, console = page
anchor = _slugify_anchor(console)
return f"[{sys_id}]({prefix}systems/{slug}.md#{anchor})"
return sys_id
+40
View File
@@ -56,5 +56,45 @@ class LinksFollowContent(unittest.TestCase):
self.assertEqual(place and place[1], console)
class OtherSpellingsOfOneSystem(unittest.TestCase):
"""Platforms and profiles spell systems their own way: the RetroArch page
listed no emulator for sega-mega-drive although genesis_plus_gx declares
sega-megadrive, and 2,057 of 4,215 emulator system lines had no link."""
def test_a_platform_system_finds_its_emulators(self):
index = gs._build_emulator_file_index({
"genesis_plus_gx": {"systems": ["sega-megadrive"]},
"np2kai": {"systems": ["pc-98"]},
})
self.assertEqual(gs._system_emulators("sega-mega-drive", index), ["genesis_plus_gx"])
self.assertEqual(gs._system_emulators("nintendo-snes", index), [])
def test_a_profile_spelling_links_to_the_platform_page(self):
import siterender
saved = dict(siterender._system_page_map)
self.addCleanup(lambda: (siterender._system_page_map.clear(),
siterender._system_page_map.update(saved)))
siterender._system_page_map.clear()
siterender._system_page_map["sega-mega-drive"] = ("sega", "Mega Drive")
self.assertIn("systems/sega.md#mega-drive", siterender._system_link("sega-megadrive"))
siterender._system_page_map["megadrive"] = ("other", "Elsewhere")
self.assertEqual(siterender._system_link("sega-megadrive"), "sega-megadrive")
def test_a_system_only_profiles_name_is_placed_by_their_files(self):
import siterender
saved = dict(siterender._system_page_map)
self.addCleanup(lambda: (siterender._system_page_map.clear(),
siterender._system_page_map.update(saved)))
siterender._system_page_map.clear()
manufacturers = {"Commodore": {"PET": [{"name": "basic4.bin"}]}}
profiles = {"vice_xpet": {"systems": ["commodore-pet"],
"files": [{"name": "basic4.bin"}]}}
gs._build_system_page_map_from_data(
manufacturers, {}, {"files": {}, "indexes": {}}, profiles)
self.assertEqual(siterender._system_page_map["commodore-pet"], ("commodore", "PET"))
if __name__ == "__main__":
unittest.main()