From 9a3e7e35b28f4ccc1f3b57903c3adeddc25509cd Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Tue, 11 Aug 2026 19:40:06 -0700 Subject: [PATCH] fix: validate accessible-name IDs against the diagram slug --- scripts/lint-skin.py | 27 ++++++++++++++++++++++----- scripts/test-lint-a11y.py | 14 ++++++++++++-- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/scripts/lint-skin.py b/scripts/lint-skin.py index 3ff21c3..c2c3154 100644 --- a/scripts/lint-skin.py +++ b/scripts/lint-skin.py @@ -168,7 +168,7 @@ class AccessibleSvgParser(HTMLParser): element.text.append(data) -def lint_accessible_svgs(text): +def lint_accessible_svgs(text, expected_slug): parser = AccessibleSvgParser(text) parser.feed(text) parser.close() @@ -265,6 +265,18 @@ def lint_accessible_svgs(text): 'bare id="title" and id="desc" are not allowed', ) + expected_title_id = f"{expected_slug}-title" + expected_description_id = f"{expected_slug}-desc" + if not placeholder_ids and ( + title_id != expected_title_id or description_id != expected_description_id + ): + add( + svg.line, + svg.offset, + f'accessible-name IDs must match file slug "{expected_slug}": ' + f'expected "{expected_title_id}" / "{expected_description_id}"', + ) + if ( labelled_by and (title_id not in labelled_by or description_id not in labelled_by) @@ -330,6 +342,10 @@ def display_path(path): return str(path) +def diagram_slug(path): + return path.stem.removeprefix("example-") + + def named_families(value): families = [] for raw_family in value.split(","): @@ -342,8 +358,8 @@ def named_families(value): return families -def lint_text(text, colors, rgb_triplets): - findings = lint_accessible_svgs(text) +def lint_text(text, colors, rgb_triplets, expected_slug): + findings = lint_accessible_svgs(text, expected_slug) def add(offset, category, message): findings.append((line_number(text, offset), offset, category, message)) @@ -473,10 +489,11 @@ def main(): try: text = path.read_text(encoding="utf-8") relative = display_path(path) + expected_slug = diagram_slug(path) if args.baseline and (path.name in baseline or relative in baseline): - findings = lint_accessible_svgs(text) + findings = lint_accessible_svgs(text, expected_slug) else: - findings = lint_text(text, colors, rgb_triplets) + findings = lint_text(text, colors, rgb_triplets, expected_slug) except OSError as error: findings = [(0, 0, "read-error", str(error))] diff --git a/scripts/test-lint-a11y.py b/scripts/test-lint-a11y.py index 37ae5ec..e7a7e4b 100644 --- a/scripts/test-lint-a11y.py +++ b/scripts/test-lint-a11y.py @@ -119,6 +119,13 @@ def main() -> int: 'bare id="title" and id="desc" are not allowed', directory, ) + require_failure( + "wrong-file-slug", + VALID_SVG, + 'accessible-name IDs must match file slug "wrong-file-slug": ' + 'expected "wrong-file-slug-title" / "wrong-file-slug-desc"', + directory, + ) require_failure( "placeholder-ids", VALID_SVG.replace("fixture-title", "[diagram-slug]-title").replace( @@ -161,9 +168,12 @@ def main() -> int: "logz": build_icons.normalize_logz(""), } for source, icon in generated_icons.items(): + slug = f"generated-{source}-icon" require_pass( - f"generated-{source}-icon", - VALID_SVG.replace("", f" {icon}\n"), + slug, + VALID_SVG.replace("fixture-title", f"{slug}-title") + .replace("fixture-desc", f"{slug}-desc") + .replace("", f" {icon}\n"), directory, )