docs: write prose without dashes or semicolons

Profiles, the wiki, comments, docstrings, command output and schema descriptions carried em-dashes, clause-joining semicolons, unicode arrows, box-drawing banners and check-mark glyphs. Each sentence was rewritten rather than having its character swapped. Hashes, paths, source_ref values and every cited file:line are unchanged, which a comparison of each parsed profile against the previous revision confirms.

validate_pr comments now say PASS and FAIL in words, and source_ref values in a profile's structured blocks render as code. test_prose_style fails if any of these comes back, in tracked files or in the generated site.
This commit is contained in:
Abdessamad Derraz committed 2026-10-19 06:47:31 +02:00
1 parent 583031eda5
commit 4231902a6c
495 files changed
+2486 -2301

No files matched your search

+6 -6
View File
@@ -76,7 +76,7 @@ def merge_mame_profile(
updated_bios.append(entry)
matched_names.add(set_name)
elif add_new:
# New BIOS set — only added to the main profile
# New BIOS set, only added to the main profile
entry = {
"name": f"{set_name}.zip",
"required": True,
@@ -88,7 +88,7 @@ def merge_mame_profile(
updated_bios.append(entry)
# Entries not matched by the scraper stay untouched
# (computer ROMs, device ROMs, etc. — outside BIOS root set scope)
# (computer ROMs, device ROMs, etc., outside BIOS root set scope)
for set_name, entry in existing_by_name.items():
if set_name not in matched_names:
updated_bios.append(entry)
@@ -296,7 +296,7 @@ def _diff_fbneo(
}
# ── Helpers ──────────────────────────────────────────────────────────
# Helpers
def _load_yaml(path: str) -> dict[str, Any]:
@@ -399,7 +399,7 @@ def _patch_core_version(text: str, version: str) -> str:
def _patch_scalar(text: str, key: str, value: str) -> str:
"""Replace a top-level scalar in-place, quoted; absent value, no change."""
"""Replace a top-level scalar in-place, quoted. An absent value changes nothing."""
if not value:
return text
return re.sub(
@@ -600,7 +600,7 @@ def _patch_block_values(block: str, entry: dict) -> str:
match = _FIELD_LINE.match(line)
if match and match["key"] == key:
if match["value"].strip().strip('"') != str(value):
# A size comment spells the old value; it goes with it.
# A size comment spells the old value, so it goes with it.
lines[i] = f" {key}: {rendered}"
break
else:
@@ -619,7 +619,7 @@ def _backup_and_write_fbneo(path: str, data: dict, hashes: dict) -> None:
FBNeo profiles have individual ROM entries with archive: field.
Patches core_version, the content values of existing entries that
changed, and appends new ROM entries. Advancing core_version alone left
a profile claiming a release whose crc32 it did not carry; comments and
a profile claiming a release whose crc32 it did not carry. Comments and
curated source_refs stay as written.
"""
p = Path(path)
+1 -1
View File
@@ -390,7 +390,7 @@ def scraper_cli(
config["systems"][sys_id]["files"].append(entry)
# Merge into existing YAML: preserve fields the scraper doesn't generate
# (data_directories, case_insensitive_fs, manually added metadata).
# The scraper replaces systems + files; everything else is preserved.
# The scraper replaces systems + files, everything else is preserved.
output_path = Path(args.output)
if output_path.exists():
with open(output_path) as f:
+2 -2
View File
@@ -95,7 +95,7 @@ def es_systems_emulators(text: str) -> tuple[set[str], set[str]]:
"""Every core es_systems.yml offers, and those that run standalone.
ES lists, per system, each emulator a user may pick and the cores under
it; configgen-defaults.yml only names the one picked by default, so
it. configgen-defaults.yml only names the one picked by default, so
reading it alone left DOSBox Staging, melonDS DS and nine other built
cores outside the pack.
"""
@@ -111,7 +111,7 @@ def es_systems_emulators(text: str) -> tuple[set[str], set[str]]:
for emulator, entries in emulators.items():
if not isinstance(entries, dict):
continue
# A standalone emulator is its own core; what it lists under it
# A standalone emulator is its own core. What it lists under it
# are machines or builds, and the non-cores among them are named
# in the overrides. Keys whose value is not a mapping
# (archs_include) describe the entry, not a core.
+5 -5
View File
@@ -12,8 +12,8 @@ BizHawk declares firmware in FirmwareDatabase.cs using four patterns:
FirmwareAndOption(sha1, size, sys, id, ...) - combined one-liner
Variable assignments (var x = File(...)) let Option() reference files
by name. Multiple options per firmware slot are ranked by status;
the Ideal non-bad option is selected as canonical.
by name. Multiple options per firmware slot are ranked by status,
and the Ideal non-bad option is selected as canonical.
"""
from __future__ import annotations
@@ -127,7 +127,7 @@ BIZHAWK_CORES = [
"handy",
"quicknes",
"genesis_plus_gx",
# Ares64 is BizHawk's N64 core only; its firmware (the 64DD IPL) is in
# Ares64 is BizHawk's N64 core only. Its firmware (the 64DD IPL) is in
# FirmwareDatabase.cs. The ares profile's thirty systems are not what
# BizHawk runs ares for.
"mupen64plus_next",
@@ -173,7 +173,7 @@ def parse_firmware_database(
"""
source = _strip_comments(source)
# ── Pass 1: collect File() definitions ────────────────────────
# Pass 1: collect File() definitions
files_by_hash: dict[str, dict] = {}
var_to_hash: dict[str, str] = {}
@@ -210,7 +210,7 @@ def parse_firmware_database(
if var_name:
var_to_hash[var_name] = key
# ── Pass 2: collect firmware slots and options ────────────────
# Pass 2: collect firmware slots and options
# FirmwareAndOption one-liner
fao_re = re.compile(
+1 -1
View File
@@ -27,7 +27,7 @@ SOURCE_URL = (
)
# Libretro cores that expect BIOS files in a subdirectory of system/.
# System.dat lists filenames flat; the scraper prepends the prefix.
# System.dat lists filenames flat, and the scraper prepends the prefix.
# ref: each core's libretro.c or equivalent -see platforms/README.md
CORE_SUBDIR_MAP = {
"nec-pc-98": "np2kai", # libretro-np2kai/sdl/libretro.c
+8 -8
View File
@@ -39,7 +39,7 @@ _REPO_URL = "https://github.com/mamedev/mame.git"
_STALE_HOURS = 24
# ── Cache ────────────────────────────────────────────────────────────
# Cache
def _load_cache() -> dict[str, Any] | None:
@@ -74,7 +74,7 @@ def _write_cache(data: dict[str, Any]) -> None:
log.info("cache written to %s", _CACHE_PATH)
# ── Git operations ───────────────────────────────────────────────────
# Git operations
def _run_git(
@@ -92,7 +92,7 @@ def _run_git(
def _sparse_clone(tag: str) -> None:
"""Clone the release the data will be labelled with, not master.
The version comes from the latest release; cloning master gave line
The version comes from the latest release. Cloning master gave line
numbers and hashes of a later revision under that release's label, and
the profiles cited lines no declared revision holds.
"""
@@ -183,7 +183,7 @@ def _cleanup() -> None:
shutil.rmtree(_CLONE_DIR)
# ── Profile discovery ────────────────────────────────────────────────
# Profile discovery
_MAME_TREES = frozenset({
@@ -223,7 +223,7 @@ def _find_mame_profiles() -> list[Path]:
return profiles
# ── Diff formatting ──────────────────────────────────────────────────
# Diff formatting
def _format_diff(
@@ -268,7 +268,7 @@ def _format_diff(
return lines
# ── Main ─────────────────────────────────────────────────────────────
# Main
def _fetch_hashes(force: bool) -> dict[str, Any]:
@@ -355,10 +355,10 @@ def release_profile(
) -> dict[str, Any]:
"""A profile for one MAME release a platform builds, from its own source.
Recalbox ships libretro/mame twice, built at 0.258 and at 0.278; the
Recalbox ships libretro/mame twice, built at 0.258 and at 0.278. The
BIOS root sets and their ROMs change between releases, so the current
MAME profile does not describe them. Each set keeps the system and the
required flag the current profile gives it; the contents and the line
required flag the current profile gives it, while the contents and the line
are the release's own.
"""
version = release.removeprefix("mame")
+3 -3
View File
@@ -9,8 +9,8 @@ MiSTer verification logic (MiSTer-devel/Downloader_MiSTer):
- file_system.py:705-712, hash_file() is a plain MD5 of the file bytes
- jobs/process_db_index_worker.py:216, an installed file is up to date when
its MD5 equals the description hash
- jobs/process_db_index_worker.py:242, integrity checks compare MD5 only;
the declared size is logged on failure but never gates the result
- jobs/process_db_index_worker.py:242, integrity checks compare MD5 only,
and the declared size is logged on failure but never gates the result
- jobs/fetch_file_worker.py:61-65, a freshly downloaded file is rejected on
MD5 mismatch
@@ -51,7 +51,7 @@ SOURCE_URL = (
DB_MEMBER = "bios_db.json"
# Files live under games/ on the SD card; base_destination carries that prefix
# Files live under games/ on the SD card, and base_destination carries that prefix
DB_ROOT = "games/"
# MiSTer core folder -> (retrobios system ID, display name, core repository)
+1 -1
View File
@@ -108,7 +108,7 @@ SYSTEMS_TREE_URL = (
)
SYSTEMS_DIR = "package/recalbox-romfs2/systems"
# One raw read per system.ini made about 150 requests and GitLab throttled
# the scrape past half an hour; GraphQL returns a batch of blobs at once.
# the scrape past half an hour. GraphQL returns a batch of blobs at once.
GRAPHQL_URL = "https://gitlab.com/api/graphql"
BLOBS_QUERY = (
"query($paths: [String!]!, $ref: String!) { project(fullPath: \"recalbox/recalbox\") "
+1 -1
View File
@@ -456,7 +456,7 @@ class Scraper(BaseScraper):
"verification_mode": "md5",
"cores": cores,
# Each component is one emulator RetroDECK ships and launches on
# its own; retroarch is the one that runs cores.
# its own, and retroarch is the one that runs cores.
"standalone_cores": [c for c in cores if c != "retroarch"],
"systems": systems,
}
+2 -2
View File
@@ -40,7 +40,7 @@ SOURCE_TEMPLATE = (
"https://raw.githubusercontent.com/ROCKNIX/distribution/{ref}/"
"projects/ROCKNIX/packages/rocknix/sources/scripts/rocknix-systems"
)
# The branch a test or a manual run can still name; a scrape reads the tag
# The branch a test or a manual run can still name. A scrape reads the tag
# of the release its YAML is labelled with.
SOURCE_URL = SOURCE_TEMPLATE.format(ref="next")
STANDALONE_TREE_URL = (
@@ -53,7 +53,7 @@ def standalone_emulators(package_names: list[str]) -> list[str]:
"""The standalone emulators ROCKNIX packages, by the names profiles use.
A package is named after its emulator with an ``-sa`` suffix
(``duckstation-sa``), once without its hyphen (``hatarisa``); both
(``duckstation-sa``), once without its hyphen (``hatarisa``), and both
spellings are kept so a profile listing either is found.
"""
names: set[str] = set()
+1 -1
View File
@@ -120,7 +120,7 @@ SLUG_MAP: dict[str, str] = {
# Mirrors are per file, not per core: a slug sharing a core with another reads
# only the firmware that core needs for its own system. The Neo Geo slugs run
# fbneo, as arcade does (index.ts:410-418), and fbneo boots every Neo Geo
# game from neogeo.zip; the fixture gives it to arcade alone. None mirrors
# game from neogeo.zip, but the fixture gives it to arcade alone. None mirrors
# every file of the slug.
FIRMWARE_MIRRORS: dict[str, dict[str, tuple[str, ...] | None]] = {
"tg16": {"turbografx-cd": None},
+2 -2
View File
@@ -2,7 +2,7 @@
A DAT states, per set, the members an emulator version expects: name, size
and CRC32. That is a recipe, and TorrentZip turns a recipe plus the ROM bytes
into the exact archive. Profiles document a few hundred sets by hand; a DAT
into the exact archive. Profiles document a few hundred sets by hand, while a DAT
documents every set of one version at once.
MAME ships its ``-listxml`` output as a release asset and FBNeo keeps its DATs
@@ -463,7 +463,7 @@ def main() -> int:
nargs="?",
const="latest",
help="download upstream instead of using --pack "
"(a MAME tag such as mame0289; bare, the newest release)",
"(a MAME tag such as mame0289, or bare for the newest release)",
)
parser.add_argument(
"--cache-dir", default=".cache/dats",
@@ -45,7 +45,7 @@ class ShellSubsetError(RuntimeError):
def _condition(text: str, env: dict[str, str]) -> bool | None:
"""`[ "${A}" = "x" -o "${B}" != "y" ]`, `-n`, `-z`; None when a clause
"""`[ "${A}" = "x" -o "${B}" != "y" ]`, `-n`, `-z`. None when a clause
tests a variable nothing has set and no other clause is true."""
results: list[bool | None] = []
for clause in re.split(r"\s+-o\s+", text):
@@ -72,12 +72,12 @@ def _condition(text: str, env: dict[str, str]) -> bool | None:
# The variables this scraper reads. Set inside a case statement, which the
# evaluator does not follow, they stop the scrape; anything else is skipped.
# evaluator does not follow, they stop the scrape. Anything else is skipped.
WATCHED = frozenset({"OPENGLES", "LIBRETRO_CORES", "EXCLUDE_LIBRETRO_CORES"})
def _expand(value: str, env: dict[str, str]) -> str:
"""${NAME} and $NAME from what is set so far; unset expands to nothing."""
"""${NAME} and $NAME from what is set so far. Unset expands to nothing."""
return re.sub(
r"\$\{(\w+)\}|\$(\w+)",
lambda m: env.get(m.group(1) or m.group(2), ""),
@@ -182,7 +182,7 @@ def device_cores(cores_mk: str, env: dict[str, str]) -> list[str]:
def device_arch(project: str, options: str) -> str:
"""The architecture Lakka builds a device for: aarch64 where its options
list it, else arm; the Generic images are x86_64."""
list it, else arm. The Generic images are x86_64."""
if project == "Generic":
return "x86_64"
return "aarch64" if re.search(r"^\s*aarch64\)", options, re.MULTILINE) else "arm"
@@ -148,7 +148,7 @@ class Scraper(BaseTargetScraper):
print(f" warning: no rp_module_id in {filename}", file=sys.stderr)
continue
# A libretro package is lr-<core> with the buildbot name hyphenated
# (lr-beetle-psx -> beetle_psx); a standalone package keeps the id
# (lr-beetle-psx -> beetle_psx), and a standalone package keeps the id
# the platform list carries (dosbox-staging).
core_name = module_id
if core_name.startswith("lr-"):
@@ -91,7 +91,7 @@ def core_names(libretro: list[str], standalone: list[str]) -> list[str]:
"""Package names as the profiles' cores: lists spell them.
A libretro package is the core's name with `-lr` (`beetle-psx-lr`,
`neocd_lr`), spelled with underscores as the buildbot names it; a
`neocd_lr`), spelled with underscores as the buildbot names it, and a
standalone package drops its `-sa` (`duckstation-sa`, `hatarisa`).
"""
names = {re.sub(r"[-_]lr$", "", package).replace("-", "_") for package in libretro}
@@ -101,7 +101,7 @@ def core_names(libretro: list[str], standalone: list[str]) -> list[str]:
# A package that builds nothing itself and pulls other cores in. idtech-lr
# installs ecwolf, prboom, tyrquake and vitaquake2 (vitaquake3 and boom3 on
# x86_64); no profile could name it.
# x86_64). No profile could name it.
METAPACKAGES = {"idtech-lr": "projects/ROCKNIX/packages/emulators/libretro/idtech-lr/package.mk"}
_IF_RE = re.compile(r'^if \[ "\$\{(\w+)\}" = "?([\w-]+)"? \]; then\n(.*?)^fi$',
re.MULTILINE | re.DOTALL)
@@ -111,7 +111,7 @@ def metapackage_cores(package_mk: str, arch: str) -> list[str]:
"""The -lr packages a metapackage depends on for one architecture.
OPENGLES_SUPPORT is yes on every ROCKNIX device (config/graphic, from
OPENGLES="mesa" in projects/ROCKNIX/options); TARGET_ARCH is the device's.
OPENGLES="mesa" in projects/ROCKNIX/options), and TARGET_ARCH is the device's.
"""
found: list[str] = []
for variable, value, body in _IF_RE.findall(package_mk):