07: Strumenti, stile e trappole
← 06 - Frontmatter e Markdown per il web · Indice
7.1 markdownlint
Il linter di riferimento (markdownlint 0.41.x, CLI markdownlint-cli2). Controlla la
semantica del documento, non solo la formattazione.
Le regole che vale la pena tenere attive su documentazione tecnica:
| Regola | Cosa impone |
|---|---|
| MD001 | niente salti nella gerarchia degli heading (H2 → H4) |
| MD025 | un solo H1 per documento (riconosce il title del frontmatter) |
| MD040 | ogni fence dichiara il linguaggio |
| MD045 | ogni immagine ha l’alt text |
| MD051 | i link #ancora puntano a heading esistenti |
| MD059 | niente “clicca qui”, “qui”, “link”, “altro” come testo di un link |
| MD024 | niente heading duplicati (romperebbero le ancore) |
| MD044 | capitalizzazione coerente dei nomi propri (JavaScript, Obsidian, Astro) |
| MD043 | struttura fissa obbligatoria, utile per template di guide |
Configurazione in .markdownlint-cli2.jsonc o .markdownlint.json:
{
"extends": "markdownlint/style/prettier",
"MD013": false,
"MD033": { "allowed_elements": ["details", "summary", "br", "kbd"] },
"MD044": { "names": ["JavaScript", "TypeScript", "Obsidian", "Astro", "Markdown", "YAML"] }
}Lo stile prettier in extends disattiva le 23 regole che litigherebbero con Prettier.
La divisione del lavoro sensata è: Prettier fa il formato, markdownlint fa la semantica.
Il frontmatter viene ignorato di default (riconosce YAML ---, TOML +++ e JSON).
7.2 Prettier
Prettier 3.9.x formatta Markdown. Cosa normalizza (verificato empiricamente):
- bullet
*e+→-(ma alterna il marker fra due liste adiacenti per non fonderle) - indentazione annidata → 2 spazi
__grassetto__→**grassetto**,*corsivo*→_corsivo_***e___→---- tabelle: celle allineate
- il frontmatter YAML viene riformattato
Cosa non tocca: setext heading, code block indentati, gli spazi finali degli hard break,
e, buona notizia, tutta la sintassi Obsidian (==, [[...]], “, #tag, callout).
proseWrap: "always"rompe i callout ObsidianVerificato: mandando a capo il testo, il titolo del callout viene fuso con la prima riga del corpo e smette di essere un titolo. Tieni il default
"preserve".
{ "proseWrap": "preserve", "printWidth": 80, "endOfLine": "lf" }7.3 Pandoc
Il convertitore universale (3.10 ad agosto 2026).
pandoc -s nota.md -o nota.html # verso HTML standalone
pandoc -s nota.md -o nota.docx # verso Word
pandoc -s nota.md -o nota.pdf # PDF (serve un motore LaTeX o typst)
pandoc -f markdown -t gfm nota.md -o github.md # normalizza verso GFMPer digerire un po’ di sintassi Obsidian:
pandoc -f markdown+mark+wikilinks_title_after_pipe+tex_math_dollars nota.md -o nota.htmlmark abilita ==evidenziato==, wikilinks_title_after_pipe gestisce [[link|testo]].
Per embed, block id e callout non esiste un’estensione: servirebbe un filtro Lua.
Nota che -f markdown (il dialetto di Pandoc), -f gfm e -f commonmark non parsano
allo stesso modo: cambia il trattamento di liste, a capo e tabelle. Se il risultato ti
sorprende, la prima cosa da controllare è quale dialetto hai dichiarato in input.
7.4 Editor
In VS Code: markdownlint (DavidAnson) e Prettier, con
"editor.formatOnSave": true. Un’accortezza: se usi gli hard break a due spazi, disattiva
files.trimTrailingWhitespace per il Markdown, altrimenti te li cancella. Oppure smetti
di usarli e passa al backslash (03 - Inline - enfasi, link, escaping).
Per il debug della sintassi, la risposta è sempre la stessa: il Dingus di CommonMark.
7.5 Stile: le regole difendibili (e il perché)
Non dogmi, ma scelte con una motivazione.
Un solo H1. In un sito il titolo viene dal frontmatter: un # nel corpo produce due
H1 nel DOM. In Obsidian il titolo è il nome del file, quindi lo stesso vale.
→ Struttura le note partendo da ##.
Nessun salto nella gerarchia. I generatori di indice (getHeadings() in Astro,
l’outline di Obsidian) costruiscono un albero per livello: un H2 seguito da un H4 produce
un indice sbagliato. Non è estetica.
Link descrittivi. Chi usa uno screen reader può farsi leggere l’elenco dei link fuori contesto: dodici voci “qui” sono inutilizzabili. È il motivo per cui è una regola del linter e non un consiglio di stile.
Una frase per riga. Il tema più discusso. I fatti:
- Righe wrappate a 80 colonne: cambiare una parola all’inizio di un paragrafo riflow tutte le righe successive → il diff git diventa un blocco illeggibile e i merge conflict si moltiplicano.
- Una frase (o clausola) per riga: il diff mostra solo la frase cambiata. Righe corte, diff puliti, nessun riflow. È il compromesso migliore oggi.
- Attenzione se scrivi in Obsidian con “Strict line breaks” disattivato: lì un a capo singolo si vede, quindi il semantic line break cambia il rendering. Provalo prima di adottarlo come regola.
Alt text sempre. E non usare la sintassi Obsidian con la dimensione al posto dell’alt.
Fence sempre con linguaggio. Serve alla colorazione, ed è metadato: bash per i
comandi, console o text per l’output, text quando davvero non c’è un linguaggio.
Riga vuota attorno a heading, liste, fence e tabelle. Molti parser sbagliano senza, e non costa nulla.
7.6 I dieci errori più comuni
- Tabella senza riga di separazione → resta testo. Serve
| --- | --- |. - Sottolista con indentazione insufficiente → diventa una lista sorella. Allinea alla colonna del testo dell’item genitore.
---dopo un paragrafo → diventa un H2 e si mangia il paragrafo. Metti una riga vuota, o usa***.a*b*cdiventa corsivo → usa i backtick o escapa.- A capo che spariscono → un invio singolo è uno spazio. Usa
\a fine riga. - Hard break cancellato dall’editor → i due spazi finali sono invisibili e fragili.
- Lista che “si allarga” → una riga vuota di troppo l’ha resa loose.
- “ pubblicato → fuori da Obsidian è testo normale.
- Cella di tabella troncata → una pipe non escapata, anche dentro il codice.
- Link
#ancorarotto → hai rinominato l’heading. Attiva MD051.
7.7 Cheatsheet
## Heading (fino a ######, sempre con lo spazio dopo i #)
*corsivo* **grassetto** ~~barrato~~ `codice`
==evidenziato== (solo Obsidian)
- lista 1. lista ordinata (scrivi sempre 1., si rinumera da sola)
- annidata: allinea alla colonna del testo del genitore
- [ ] task - [x] fatto
> citazione
> [!NOTE] callout/alert (5 tipi maiuscoli su GitHub, tanti minuscoli in Obsidian)
>
[testo](url) [testo](url "titolo") [testo][rif] 
<https://autolink.it> https://nudo-solo-in-gfm.it
[rif]: https://esempio.it
a capo forzato: backslash a fine riga \
riga successiva
| col | col |
| --- | ---:|
| a | 1 |
```linguaggio
blocco di codice, dichiara sempre il linguaggio
```
--- separatore (ma non subito dopo un paragrafo: usa ***)
nota a piè di pagina[^1]
[^1]: testo della nota7.8 Dove continuare
- CommonMark spec: la reference, con gli esempi.
- Dingus: il debugger.
- GFM spec e la pagina docs di GitHub.
- Obsidian Flavored Markdown.
- markdownlint, elenco regole.
- Pandoc manual: enorme, ma è la mappa completa dei dialetti.
7.9 Manutenzione di queste note
Scritte il 21 agosto 2026 su CommonMark 0.31.2 e GFM 0.29. Gli esempi ✅ sono stati eseguiti con markdown-it-py 4.0.0 (preset CommonMark).
Markdown si muove poco: la specifica è ferma dal 2024 e GFM dal 2019. Quello che cambia sono gli strumenti (Obsidian, Astro, Prettier) e le feature aggiunte dai siti. Se una cosa qui non torna, il primo sospetto è che sia cambiato un tool, non il formato.