Discussion

Compétence de Vérification d'Accessibilité Markdown

De Wikiprompt, l’encyclopédie libre de prompts

Fatih Kadir Akın

10 oct. 2026

Compétence de Vérification d'Accessibilité Markdown Définition complète d'une compétence pour un agent IA qui examine des documents Markdown pour l'accessibilité, rédige des textes alternatifs, et renvoie une liste de corrections ou un fichier corrigé. Comprend un flux de travail, des guides de référence, des modèles, un exemple de révision, et un script de vérification en Python.

Contenu du PromptEnregistrer

🌐
--- name: markdown-accessibility-checker description: Examine la documentation Markdown (README, sites de documentation, wikis, articles de blog, journaux de modifications) pour l'accessibilité - texte alternatif manquant ou de mauvaise qualité pour les images, structure des titres, texte de lien vague ou dupliqué, URL brutes, en-têtes de tableau vides, instructions basées uniquement sur la couleur, TOUT EN MAJUSCULES et puces émoji - puis rédige un bon texte alternatif pour chaque image à partir du contexte et renvoie une liste de corrections ou un fichier corrigé. À utiliser lorsqu'un utilisateur demande de "vérifier l'accessibilité de mon README", "rédiger un texte alternatif pour ces images", "rendre nos docs compatibles avec les lecteurs d'écran", ou souhaite une vérification de l'accessibilité pour du Markdown dans un environnement CI. --- # Vérificateur d'accessibilité Markdown Vous rendez les documents Markdown accessibles à tous, y compris aux personnes utilisant des lecteurs d'écran, la navigation au clavier, la loupe ou des aides à la lecture. Vous trouvez les problèmes qu'un script peut détecter, puis vous effectuez la partie qu'un script ne peut pas faire : rédiger un texte alternatif et un texte de lien pertinents qui correspondent à l'objectif du document. ## Fichiers dans cette compétence - `scripts/check_md_a11y.py` - analyse les fichiers ou dossiers Markdown et signale les problèmes avec les numéros de ligne et les niveaux de gravité (bibliothèque standard Python 3 uniquement) - `references/alt-text-guide.md` - comment rédiger un texte alternatif par type d'image (captures d'écran, diagrammes, graphiques, photos, logos, badges, images décoratives) - `references/structure-and-links.md` - titres, texte de lien, tableaux, listes, emphase, et la signification de chaque règle dans le script - `templates/a11y-review.md` - le rapport de révision et la feuille de travail pour le texte alternatif - `examples/example-readme-review.md` - une révision complète d'un README de projet ## Flux de travail ### 1. Définir le périmètre de la révision Demandez quels fichiers ou dossiers vérifier, qui les lit (développeurs, utilisateurs finaux, étudiants), et si l'utilisateur souhaite un rapport, un fichier corrigé, ou les deux. Si les documents sont rendus par un générateur de site, demandez s'il ajoute son propre titre de page (auquel cas le Markdown peut ne pas avoir besoin d'un H1). ### 2. Exécuter le vérificateur ```bash python3 scripts/check_md_a11y.py README.md docs/ python3 scripts/check_md_a11y.py docs/ --json python3 scripts/check_md_a11y.py docs/ --fail-on warn # pour CI ``` Il ignore les blocs de code délimités et le code en ligne. HIGH signifie que du contenu est perdu pour certains lecteurs (texte alternatif manquant, lien vide, titre vide), WARN doit être corrigé, INFO nécessite un examen humain. Si vous ne pouvez pas exécuter le script, vérifiez les mêmes règles en lisant le fichier et mentionnez-le. ### 3. Rédiger le texte alternatif Pour chaque image signalée, et pour chaque image avec un texte alternatif existant, déterminez son objectif à l'aide de `references/alt-text-guide.md` : - Lisez le texte autour de l'image : à quoi sert l'image à ce stade du document ? - Si vous pouvez voir l'image, décrivez ce qui est important pour cet objectif. Si vous ne le pouvez pas, demandez à l'utilisateur, ou rédigez un brouillon clairement marqué à partir du nom de fichier et du contexte (par exemple "BROUILLON : à vérifier par rapport à l'image"). - Les images décoratives reçoivent un texte alternatif vide ; dans Markdown, préférez les supprimer, ou utilisez le HTML `<img alt="">`. Remplissez la feuille de travail pour le texte alternatif dans `templates/a11y-review.md`. ### 4. Corriger la structure et les liens Appliquez `references/structure-and-links.md` : un seul H1, pas de niveaux sautés, de vrais titres au lieu de lignes en gras, un texte de lien descriptif et unique, des tableaux avec en-têtes, des instructions qui ne reposent pas uniquement sur la couleur. ### 5. Livrer - Rapport : remplissez `templates/a11y-review.md`, comme dans `examples/example-readme-review.md`, en commençant par les corrections les plus importantes. - Fichier corrigé : renvoyez le Markdown complet avec les corrections appliquées et une courte liste de modifications. Ne changez pas le sens, les exemples de code ou les destinations des liens. - Réexécutez le vérificateur sur le fichier corrigé et incluez les compteurs avant et après. ## Règles - N'inventez jamais ce qu'une image montre. Si vous ne l'avez pas vue, marquez le texte alternatif comme brouillon. - Gardez le texte alternatif court (généralement moins de 150 caractères) ; placez les longues explications (graphiques, diagrammes) dans le texte ou une légende et mentionnez-le dans le texte alternatif. - Ne commencez pas le texte alternatif par "image de" ou "photo de". - N'oubliez pas que les vérifications automatisées ne trouvent qu'une partie des problèmes ; mentionnez toujours ce qui nécessite encore une vérification manuelle (contraste des couleurs dans les images, ordre de lecture, sous-titres vidéo). - Respectez la voix de l'auteur ; corrigez l'accessibilité, pas le style. FILE:references/alt-text-guide.md # Guide du texte alternatif Le texte alternatif remplace l'image pour les personnes qui ne peuvent pas la voir. Demandez-vous : "Si je lis ce document à voix haute, que dirais-je à ce stade au lieu de montrer l'image ?" La réponse dépend de la raison pour laquelle l'image est là, pas seulement de ce qu'elle contient. ## Principes de base - Soyez précis et court : généralement 5 à 20 mots, rarement plus de 150 caractères. - Commencez par la partie importante. Ne commencez pas par "image de", "photo de" ou "capture d'écran de" sauf si le type lui-même est important ("Capture d'écran" peut aider lorsque le lecteur doit trouver le même écran). - Terminez par un point pour que les lecteurs d'écran marquent une pause. - Ne répétez pas mot pour mot la légende ou la phrase à côté de l'image. - Incluez le texte qui apparaît dans l'image si le lecteur en a besoin (libellés de boutons, messages d'erreur). ## Par type d'image ### Captures d'écran d'une application ou d'un site web Indiquez l'écran et la seule chose que le lecteur doit remarquer. - Faible : "capture d'écran" - Mieux : "Écran des paramètres avec le bouton Unités réglé sur Métrique." ### Images principales et bannières Si elle ne sert qu'à créer une ambiance, elle est décorative. Si elle montre le produit, décrivez-la en une phrase. - "Trailhead Weather sur un téléphone, montrant des prévisions sur trois jours pour un col de montagne." ### Diagrammes et organigrammes Donnez l'idée principale dans le texte alternatif, et la structure complète dans le texte ou une liste juste après l'image. - Texte alternatif : "Diagramme d'architecture : l'application mobile appelle l'API, qui lit dans un cache de prévisions et un fournisseur de données météo. Détails dans la liste ci-dessous." ### Graphiques et diagrammes statistiques Donnez le type, le sujet et le point clé à retenir ; placez les données dans un tableau si les lecteurs ont besoin des chiffres. - "Graphique en courbes des utilisateurs actifs quotidiens, de janvier à juin 2026, passant de 2 000 à 9 500 avec une baisse en avril." ### Photos Décrivez ce qui est important pour l'objectif du document : sujet, action, décor. - "Sentier de crête enneigé avec des balises orange menant à un refuge." ### Logos Utilisez le nom de l'organisation ou du produit, et ajoutez "logo" uniquement si cela aide : "Logo Trailhead Weather." Lorsque le logo est un lien, décrivez la destination : "Accueil Trailhead Weather." ### Badges (état de build, version, licence) Écrivez l'information que le badge affiche : "Build : réussi", "Licence : MIT", "Version 2.4.1". ### Icônes dans le texte ou les liens Si l'icône a une fonction, décrivez la fonction ("Télécharger") ; si elle répète le texte à proximité, elle est décorative. ### GIF animés et courtes vidéos Décrivez ce qui se passe : "Animation : faire glisser une épingle sur la carte ajoute un nouveau point de départ à la liste." Les vidéos nécessitent également des sous-titres et, pour un contenu important, une alternative textuelle. ### Images décoratives Séparateurs, textures de fond et ornements purement visuels. En HTML, utilisez `alt=""` pour que les lecteurs d'écran les ignorent. En Markdown, `![](divider.png)` est ambigu (souvent une erreur), préférez donc supprimer l'image ou utiliser `<img src="divider.png" alt="">`. ## Erreurs courantes - Noms de fichiers comme texte alternatif : "IMG_2041.jpg", "hero-final-v3". - Un seul mot : "image", "logo", "graphique". - Remplissage de mots-clés pour les moteurs de recherche. - Texte alternatif différent pour la même image utilisée à plusieurs endroits. - Décrire les couleurs ou la mise en page alors que le lecteur a besoin de l'information, pas de l'apparence. FILE:references/structure-and-links.md # Structure, liens et signification de chaque règle Les utilisateurs de lecteurs d'écran naviguent souvent dans un document par les titres ou par les liens. Une bonne structure est ce qui rend cela possible. ## Titres | Règle | Gravité | Pourquoi | Correction | |---|---|---|---| | titre-vide | HIGH | Un titre vide est annoncé comme "titre de niveau 2" sans rien derrière. | Ajoutez du texte ou supprimez le #. | | pas-de-h1 | WARN | La page n'a pas de titre dans le plan des titres. | Commencez par un `# Titre`. Ignorez cette règle si le générateur de site ajoute le H1 à partir des métadonnées. | | plusieurs-h1 | WARN | Plusieurs titres confondent le plan. | Gardez un seul H1 ; utilisez `##` pour les sections. | | saut-de-titre | WARN | Passer de H2 à H4 suggère une section manquante. | Utilisez le niveau suivant (H3). Choisissez les niveaux pour la structure, pas pour la taille de police. | | faux-titre | INFO | Une ligne en gras ressemble à un titre mais n'est pas dans le plan. | Utilisez un vrai titre si elle commence une section ; gardez le gras s'il s'agit simplement d'une emphase. | | pas-de-titres | INFO | Un long texte sans titres est difficile à parcourir. | Ajoutez des titres de section tous les quelques paragraphes. | ## Liens | Règle | Gravité | Pourquoi | Correction | |---|---|---|---| | lien-vide | HIGH | Le lien n'a pas de nom accessible. | Ajoutez un texte descriptif. | | lien-vague | WARN | "Cliquez ici" ou "en savoir plus" ne signifie rien dans une liste de liens. | Nommez la destination : "télécharger la dernière version", "guide d'installation". | | même-texte-url-différente | WARN | Deux liens appelés "docs" qui vont à des endroits différents sont impossibles à distinguer. | Rendez chaque texte unique : "Référence API", "guide d'installation". | | url-comme-texte-de-lien | INFO | Les longues URL sont lues caractère par caractère. | Utilisez une courte description ; ne gardez l'URL que si les lecteurs doivent la copier. | | url-brute | INFO | Comme ci-dessus, et pas toujours cliquable. | Enveloppez-la dans un lien descriptif. | Conseils pour le texte de lien : placez les mots importants en premier, gardez-le court, indiquez quand un lien ouvre un fichier ("fiche tarifaire (PDF, 2 Mo)"), et n'utilisez pas le mot "lien" dans le texte. ## Images | Règle | Gravité | Pourquoi | |---|---|---| | img-alt-manquant | HIGH | `![](file.png)` ne fournit aucune alternative ; certains lecteurs annoncent le nom du fichier. | | img-sans-alt | HIGH | `<img>` sans attribut alt ; les lecteurs d'écran utilisent le nom du fichier par défaut. | | img-alt-générique | WARN | "image", "capture d'écran", "logo" seuls ne portent aucune information. | | img-alt-nom-fichier | WARN | "IMG_2041.jpg" n'est pas une description. | | img-alt-long | WARN | Un texte alternatif très long ne peut pas être parcouru ; déplacez les détails dans le texte. | | img-alt-redondant | INFO | "Image de" est redondant ; les lecteurs d'écran disent déjà "image". | | img-décorative | INFO | `alt=""` masque l'image ; confirmez qu'elle est réellement décorative. | Voir `alt-text-guide.md` pour savoir comment rédiger le texte. ## Tableaux - tableau-en-tête-vide (WARN) : chaque colonne a besoin d'un en-tête pour que les lecteurs d'écran puissent annoncer "Pro, Jours de prévision, 10". Ajoutez un en-tête tel que "Fonctionnalité" à la première colonne. - Utilisez des tableaux pour les données, pas pour la mise en page. Gardez-les petits ; divisez les tableaux très larges. ## Autres règles - couleur-seule (WARN) : "Appuyez sur le bouton vert" ne fonctionne pas pour les personnes daltoniennes et les utilisateurs de lecteurs d'écran. Nommez le bouton : "Sélectionnez Enregistrer (le bouton vert)". - tout-majuscules (INFO) : un long texte TOUT EN MAJUSCULES est plus difficile à lire, et certains lecteurs d'écran épellent les mots courts en majuscules lettre par lettre. Utilisez la casse normale et le gras pour l'emphase. - puce-émoji (INFO) : les émojis sont lus à voix haute par leur nom ("coche blanche Prévisions horaires"). Utilisez des marqueurs de liste normaux et gardez les émojis rares et significatifs. ## Non vérifié par le script (à vérifier manuellement) - Si le texte alternatif est exact et utile. - Le contraste des couleurs et le texte dans les images (captures d'écran avec petit texte, graphiques à faible contraste). - L'ordre de lecture des mises en page complexes et les blocs HTML intégrés dans le Markdown. - Les sous-titres et transcriptions pour les vidéos et l'audio. - Le langage clair : phrases courtes, jargon défini et noms de sections descriptifs. FILE:templates/a11y-review.md # Révision de l'accessibilité : <document ou dossier> Date : <AAAA-MM-JJ> Fichiers vérifiés : <n> (<liste ou dossier>) Public : <qui lit ces docs> Exécution du vérificateur : `python3 scripts/check_md_a11y.py <chemins>` -> HIGH <n>, WARN <n>, INFO <n> ## Corrections prioritaires (impact le plus fort d'abord) 1. <correction> (<fichier:ligne>) 2. <correction> 3. <correction> ## Feuille de travail pour le texte alternatif | Fichier:ligne | Image | Objectif dans le document | Texte alternatif actuel | Nouveau texte alternatif | Image vue ? | |---|---|---|---|---|---| | | | informatif / fonctionnel / décoratif / complexe | | | oui / brouillon | ## Titres - Plan actuel : <H1 ... / H2 ... / H4 ...> - Plan proposé : <H1 ... / H2 ... / H3 ...> ## Liens | Fichier:ligne | Texte actuel | Nouveau texte | Destination | |---|---|---|---| | | | | | ## Autres constatations | Fichier:ligne | Règle | Modification | |---|---|---| | | | | ## Après corrections Réexécution du vérificateur : HIGH <n>, WARN <n>, INFO <n> (les éléments INFO restants sont expliqués ci-dessous). - <élément INFO : raison pour laquelle il est acceptable> ## Vérifications manuelles encore nécessaires - <par exemple : contraste du texte dans les captures d'écran, sous-titres vidéo> FILE:examples/example-readme-review.md # Exemple : révision de l'accessibilité d'un README de projet ## La demande "Le README de notre application open source reçoit beaucoup de trafic. Un utilisateur qui dépend d'un lecteur d'écran a dit qu'il était difficile à suivre. Pouvez-vous le vérifier et le corriger ? L'image principale est l'application sur un téléphone avec les prévisions sur 3 jours ; app-main.png est l'écran principal avec la température horaire, le vent et la limite des neiges ; le badge est notre statut de build." ## Exécution du vérificateur (avant) ``` $ python3 scripts/check_md_a11y.py README.md Markdown accessibility check: 1 file(s), 3 image(s) HIGH 2 WARN 8 INFO 5 README.md (3 images, 4 headings): 15 finding(s) 3 HIGH img-missing-alt Image hero.png has empty alt text; describe it, or confirm it is purely decorative. 5 INFO all-caps Long ALL CAPS text is hard to read and some screen readers spell it letter by letter. 9 WARN vague-link Link text "here" does not say where it goes; describe the destination. 9 WARN vague-link Link text "click here" does not say where it goes; describe the destination. 11 WARN img-generic-alt Alt text "screenshot" for app-main.png is generic; say what the image shows or why it is there. 13 HIGH img-no-alt <img src="docs/img/badge.svg"> has no alt attribute. 15 WARN heading-skip Heading level jumps from H2 to H4 ("Configuration"); use H3. 17 WARN color-only Instruction relies on color; add the label, shape, or position too. 19 INFO fake-heading Bold line "Features" looks like a heading; use a real # heading if it starts a section. 21 INFO emoji-bullet Emoji used as a bullet is read aloud by name; use a list marker and put meaning in words. 22 INFO emoji-bullet Emoji used as a bullet is read aloud by name; use a list marker and put meaning in words. 24 WARN table-empty-header Table header has 1 empty cell(s); every column needs a header. 28 WARN same-text-different-url Link text "docs" points to 2 different URLs; make each text unique. 28 INFO bare-url Bare URL https://example.org/docs; screen readers spell it out. Use [descriptive text](https://example.org/docs). 35 WARN multiple-h1 2 H1 headings (lines 1, 35); keep one title and use ## for sections. ``` Le `![](not-an-image.png)` dans le bloc de code bash et l'exemple de code en ligne sur la dernière ligne ont été correctement ignorés. ## La révision (modèle rempli, raccourci) # Révision de l'accessibilité : README.md Public : randonneurs et contributeurs, beaucoup arrivent via les moteurs de recherche. Exécution du vérificateur : HIGH 2, WARN 8, INFO 5. ### Corrections prioritaires 1. Donnez un vrai texte alternatif à l'image principale et au badge de build (lignes 3 et 13). 2. Remplacez "ici" et "cliquez ici" par un texte de lien qui nomme la destination (ligne 9). 3. Corrigez le plan : "Configuration" devient H3, "Features" devient un vrai H3, et le deuxième H1 "Contributing" devient H2. 4. Nommez le bouton Enregistrer au lieu de seulement sa couleur (ligne 17). 5. Donnez un en-tête à la première colonne du tableau (ligne 24). ### Feuille de travail pour le texte alternatif | Fichier:ligne | Image | Objectif | Texte alternatif actuel | Nouveau texte alternatif | Vu ? | |---|---|---|---|---|---| | README.md:3 | hero.png | informatif : montre le produit | (vide) | Trailhead Weather sur un téléphone, montrant des prévisions sur trois jours pour un col de montagne. | décrit par l'utilisateur | | README.md:11 | app-main.png | informatif : ce que montre l'écran principal | capture d'écran | Écran principal avec la température horaire, le vent et la limite des neiges pour le point de départ sélectionné. | décrit par l'utilisateur | | README.md:13 | badge.svg | informatif : statut du build | (pas d'alt) | Build : réussi | décrit par l'utilisateur | ### Titres - Avant : H1 Trailhead Weather / H2 Install / H4 Configuration / H1 Contributing (plus une ligne en gras "Features"). - Après : H1 Trailhead Weather / H2 Install / H3 Configuration / H3 Features / H2 Contributing. ### Liens | Ligne | Texte actuel | Nouveau texte | Destination | |---|---|---|---| | 9 | ici | Télécharger la dernière version | https://example.org/releases | | 9 | cliquez ici | guide d'installation | docs/guides/setup.md | | 28 | docs (URL brute + "docs") | Référence API | https://example.org/docs | | 28 | docs | guide d'installation | docs/guides/setup.md | ### Autres constatations | Ligne | Règle | Modification | |---|---|---| | 5 | tout-majuscules | Casse normale dans la note en gras. | | 17 | couleur-seule | "Sélectionnez Enregistrer (le bouton vert en bas des paramètres)". | | 21-22 | puce-émoji | Éléments de liste "-" normaux. | | 24 | tableau-en-tête-vide | En-tête de la première colonne "Fonctionnalité". | ### README corrigé (extrait) ```markdown # Trailhead Weather ![Trailhead Weather sur un téléphone, montrant des prévisions sur trois jours pour un col de montagne.](docs/img/hero.png) Trailhead Weather montre des prévisions de montagne pour les randonneurs. **Note : ce projet est encore en version bêta et les choses casseront souvent.** ## Install [Télécharger la dernière version](https://example.org/releases), ou suivez le [guide d'installation](docs/guides/setup.md). <img src="docs/img/badge.svg" width="90" alt="Build : réussi"> ### Configuration Sélectionnez Enregistrer (le bouton vert en bas des paramètres) pour enregistrer vos paramètres. ### Features - Prévisions horaires - Bulletins d'avalanche | Fonctionnalité | Gratuit | Pro | |---|---|---| | Jours de prévision | 3 | 10 | ``` ### Après corrections ``` $ python3 scripts/check_md_a11y.py README-fixed.md Markdown accessibility check: 1 file(s), 3 image(s) HIGH 0 WARN 0 INFO 0 ``` ### Vérifications manuelles encore nécessaires - L'image principale a un petit texte sur l'écran du téléphone ; le texte alternatif porte le message clé, ce qui est acceptable ici. - Si le README est un jour transformé en page de site de documentation, confirmez que le site n'ajoute pas un deuxième H1. ## Pourquoi c'est une bonne réponse - Le texte alternatif décrit l'objectif de chaque image, en utilisant ce que l'utilisateur a dit que les images montrent au lieu de deviner. - Les liens et les titres sont corrigés pour la façon dont les utilisateurs de lecteurs d'écran naviguent : par liste de liens et par plan de titres. - La correction est vérifiée en réexécutant le vérificateur, et les vérifications manuelles restantes sont listées honnêtement. FILE:scripts/check_md_a11y.py #!/usr/bin/env python3 """Check Markdown files for common accessibility problems. Usage: python3 check_md_a11y.py README.md docs/ # files and folders (*.md, *.markdown) python3 check_md_a11y.py docs/ --json cat page.md | python3 check_md_a11y.py - python3 check_md_a11y.py docs/ --fail-on warn # exit 1 on WARN too (for CI) Checks (code blocks and inline code are ignored): images missing alt text, file-name or generic alt ("image", "screenshot"), redundant "image of ..." openers, very long alt, HTML <img> without alt, empty alt (fine only for decorative images) headings no H1 or more than one H1, skipped levels (H2 -> H4), empty headings, bold lines used as fake headings links empty link text, vague text ("click here", "read more", "here"), bare URLs, the same text pointing to different URLs tables empty header cells other ALL CAPS sentences, emoji used as bullets, color-only instructions Severities: HIGH (blocks understanding), WARN (should fix), INFO (check by hand). Exit code: 0 no HIGH, 1 HIGH found (or WARN with --fail-on warn), 2 usage error. Standard library only. """ import argparse import json import os import re import sys GENERIC_ALT = {"image", "img", "picture", "pic", "photo", "screenshot", "screen shot", "graphic", "icon", "logo", "diagram", "chart", "figure", "untitled", "alt", "alt text", "banner", "placeholder"} VAGUE_LINK = {"click here", "here", "click", "read more", "more", "learn more", "link", "this", "this link", "this page", "go", "details", "more info", "info", "see here", "check it out"} REDUNDANT_START = re.compile(r"^(an? )?(image|picture|photo|screenshot|graphic) (of|showing)\b", re.I) FILE_ALT = re.compile(r"^[\w\-. ]+\.(png|jpe?g|gif|svg|webp|bmp|tiff?)$|^(img|image|dsc|screenshot)[_\- ]?\d+", re.I) IMG_MD = re.compile(r"!\[([^\]]*)\]\(\s*<?([^)\s>]*)>?(?:\s+\"[^\"]*\")?\s*\)") IMG_REF = re.compile(r"!\[([^\]]*)\]\[[^\]]*\]") LINK_MD = re.compile(r"(?<!!)\[([^\]]*)\]\(\s*<?([^)\s>]*)>?(?:\s+\"[^\"]*\")?\s*\)") HTML_IMG = re.compile(r"<img\b[^>]*>", re.I) BARE_URL = re.compile(r"(?<![(<\"'=\[])\bhttps?://[^\s)>\]]+") COLOR_ONLY = re.compile(r"\b(click|press|tap|select|choose|use)\b[^.]{0,30}\b(red|green|blue|yellow|orange|purple)\b(?! *\()", re.I) EMOJI_BULLET = re.compile(r"^\s*[\u2705\u274c\u2b50\u27a1\u2714\u2716\U0001F300-\U0001FAFF]\ufe0f?\s+\S") def strip_inline_code(line): return re.sub(r"`+[^`]*`+", lambda m: " " * len(m.group(0)), line) def check_text(text, name): findings = [] def add(sev, line, rule, msg): findings.append({"file": name, "line": line, "severity": sev, "rule": rule, "message": msg}) lines = text.replace("\r\n", "\n").split("\n") in_fence, fence = False, "" headings, link_targets = [], {} images = 0 prev_blank = True for no, raw in enumerate(lines, 1): stripped = raw.strip() m = re.match(r"^\s{0,3}(`{3,}|~{3,})", raw) if m: if not in_fence: in_fence, fence = True, m.group(1)[0] * 3 elif stripped.startswith(fence): in_fence = False continue if in_fence or raw.startswith(" ") and prev_blank and not stripped.startswith(("-", "*", "+")): prev_blank = not stripped if not in_fence else prev_blank continue line = strip_inline_code(raw) hm = re.match(r"^\s{0,3}(#{1,6})(\s+|$)(.*?)\s*#*\s*$", line) if hm: level, title = len(hm.group(1)), hm.group(3).strip() headings.append((no, level, title)) if not title: add("HIGH", no, "empty-heading", f"Empty H{level} heading; screen reader users navigate by headings.") elif re.fullmatch(r"\s*(\*\*|__)[^*_]{2,80}(\*\*|__):?\s*", line) and prev_blank: add("INFO", no, "fake-heading", f"Bold line \"{stripped.strip('*_:')}\" looks like a heading; use a real # heading if it starts a section.") images += len(IMG_MD.findall(line)) + len(IMG_REF.findall(line)) + len(HTML_IMG.findall(line)) for alt, src in IMG_MD.findall(line): check_alt(add, no, alt, src) for alt in IMG_REF.findall(line): check_alt(add, no, alt, "(reference)") for tag in HTML_IMG.findall(line): am = re.search(r"\balt\s*=\s*(\"([^\"]*)\"|'([^']*)'|(\S+))", tag, re.I) src = re.search(r"\bsrc\s*=\s*[\"']?([^\"'\s>]+)", tag, re.I) src = src.group(1) if src else "?" if not am: add("HIGH", no, "img-no-alt", f"<img src=\"{src}\"> has no alt attribute.") else: check_alt(add, no, am.group(2) if am.group(2) is not None else (am.group(3) if am.group(3) is not None else am.group(4)), src, html=True) no_images = IMG_MD.sub(" ", line) for text_, url in LINK_MD.findall(no_images): label = re.sub(r"[*_`]", "", text_).strip() if not label: add("HIGH", no, "empty-link", f"Link to {url or '(no url)'} has no text; screen readers will read the URL or nothing.") elif label.lower().rstrip(".!:") in VAGUE_LINK: add("WARN", no, "vague-link", f"Link text \"{label}\" does not say where it goes; describe the destination.") elif re.fullmatch(r"https?://\S+", label): add("INFO", no, "url-as-link-text", f"Link text is a raw URL ({label[:60]}); use a short description.") if label: link_targets.setdefault(label.lower(), {}).setdefault(url, no) for url in BARE_URL.findall(LINK_MD.sub(" ", no_images)): add("INFO", no, "bare-url", f"Bare URL {url[:60]}; screen readers spell it out. Use [descriptive text]({url[:40]}).") if "|" in line and re.match(r"^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$", line) and no > 1: header = lines[no - 2].strip().strip("|") cells = [c.strip() for c in header.split("|")] if any(not c for c in cells): add("WARN", no - 1, "table-empty-header", f"Table header has {sum(1 for c in cells if not c)} empty cell(s); every column needs a header.") run = longest = 0 for w in re.findall(r"[A-Za-z]+", line): run = run + 1 if w.isupper() and (len(w) > 1 or w in "AI") else 0 longest = max(longest, run) if longest >= 5 and not hm: add("INFO", no, "all-caps", "Long ALL CAPS text is hard to read and some screen readers spell it letter by letter.") if EMOJI_BULLET.match(line): add("INFO", no, "emoji-bullet", "Emoji used as a bullet is read aloud by name; use a list marker and keep emoji rare and meaningful.") cm = COLOR_ONLY.search(line) if cm: between = line[cm.end(1):cm.start(2)] inside_parens = line[:cm.start(2)].count("(") > line[:cm.start(2)].count(")") names_label = re.match(r"\s+(\*\*|\"|')?[A-Z]", between) # "Select Save ..." or "Press **Save**" if inside_parens or names_label: cm = None if cm: add("WARN", no, "color-only", "Instruction relies on color; add the label, shape, or position too.") prev_blank = not stripped h1 = [h for h in headings if h[1] == 1] if headings and not h1: add("WARN", headings[0][0], "no-h1", "Document has no H1; start with one # title.") if len(h1) > 1: add("WARN", h1[1][0], "multiple-h1", f"{len(h1)} H1 headings (lines {', '.join(str(h[0]) for h in h1)}); keep one title and use ## for sections.") for (pno, plev, _), (no, lev, title) in zip(headings, headings[1:]): if lev > plev + 1: add("WARN", no, "heading-skip", f"Heading level jumps from H{plev} to H{lev} (\"{title[:50]}\"); use H{plev + 1}.") if not headings and len([l for l in lines if l.strip()]) > 15: add("INFO", 1, "no-headings", "Long document with no headings; add headings so readers can navigate.") for label, targets in link_targets.items(): if len(targets) > 1 and label not in VAGUE_LINK: first = min(targets.values()) add("WARN", first, "same-text-different-url", f"Link text \"{label}\" points to {len(targets)} different URLs; make each text unique.") order = {"HIGH": 0, "WARN": 1, "INFO": 2} findings.sort(key=lambda f: (f["line"], order[f["severity"]])) return findings, len(headings), images def check_alt(add, no, alt, src, html=False): a = alt.strip() base = os.path.basename(src) if src else "" if a == "" and html: add("INFO", no, "img-decorative", f"<img src=\"{base}\"> has alt=\"\" (marked decorative); confirm it carries no information.") return if a == "" and src: add("HIGH", no, "img-missing-alt", f"Image {base or src} has empty alt text; describe it, or confirm it is purely decorative.") return low = a.lower().rstrip(".") if low in GENERIC_ALT: add("WARN", no, "img-generic-alt", f"Alt text \"{a}\" for {base} is generic; say what the image shows or why it is there.") elif FILE_ALT.search(a) or (base and low == os.path.splitext(base)[0].lower()): add("WARN", no, "img-filename-alt", f"Alt text \"{a}\" looks like a file name; describe the image instead.") elif REDUNDANT_START.match(a): add("INFO", no, "img-redundant-alt", f"Alt text starts with \"{' '.join(a.split()[:3])}\"; screen readers already say 'image', so start with the content.") if len(a) > 150: add("WARN", no, "img-long-alt", f"Alt text is {len(a)} characters; keep it under about 150 and move details to the surrounding text or a caption.") def collect(paths): files = [] for p in paths: if p == "-": files.append("-") elif os.path.isdir(p): for root, dirs, names in os.walk(p): dirs[:] = sorted(d for d in dirs if not d.startswith(".") and d != "node_modules") files += [os.path.join(root, n) for n in sorted(names) if n.lower().endswith((".md", ".markdown"))] elif os.path.isfile(p): files.append(p) else: raise FileNotFoundError(p) return files def main(): ap = argparse.ArgumentParser(description="Markdown accessibility checker") ap.add_argument("paths", nargs="+", help="Markdown files, folders, or - for stdin") ap.add_argument("--json", action="store_true") ap.add_argument("--fail-on", choices=["high", "warn"], default="high") args = ap.parse_args() try: files = collect(args.paths) except FileNotFoundError as e: print(f"error: path not found: {e}", file=sys.stderr) return 2 if not files: print("error: no Markdown files (*.md, *.markdown) found", file=sys.stderr) return 2 all_findings, stats = [], [] for f in files: text = sys.stdin.read() if f == "-" else open(f, encoding="utf-8", errors="replace").read() name = "<stdin>" if f == "-" else f found, nhead, images = check_text(text, name) stats.append({"file": name, "images": images, "headings": nhead, "findings": len(found)}) all_findings += found counts = {s: sum(1 for x in all_findings if x["severity"] == s) for s in ("HIGH", "WARN", "INFO")} if args.json: print(json.dumps({"files": stats, "counts": counts, "findings": all_findings}, indent=2)) else: print(f"Markdown accessibility check: {len(files)} file(s), {sum(s['images'] for s in stats)} image(s)") print(f"HIGH {counts['HIGH']} WARN {counts['WARN']} INFO {counts['INFO']}") for s in stats: items = [x for x in all_findings if x["file"] == s["file"]] print(f"\n{s['file']} ({s['images']} images, {s['headings']} headings): {len(items)} finding(s)") for x in items: print(f" {x['line']:>4} {x['severity']:<4} {x['rule']:<24} {x['message']}") print("\nAutomated checks cover only part of accessibility; review alt text meaning, reading order, and contrast by hand.") bad = counts["HIGH"] + (counts["WARN"] if args.fail_on == "warn" else 0) return 1 if bad else 0 if __name__ == "__main__": sys.exit(main())

Connectez-vous pour voir le prompt complet

Continuer avec:

En vous connectant, vous acceptez nos Conditions et Confidentialité

Utilisation

Ce prompt est conçu pour être utilisé avec productivity. Copiez le contenu ci-dessus et collez-le dans votre outil d’IA préféré.

Pour de meilleurs résultats, personnalisez les espaces réservés (indiqués par des crochets ou des majuscules) selon vos besoins.

Références

Catégories :productivity| prompts.chat| markdown| accessibility

Discussion