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:

RegolaCosa impone
MD001niente salti nella gerarchia degli heading (H2 → H4)
MD025un solo H1 per documento (riconosce il title del frontmatter)
MD040ogni fence dichiara il linguaggio
MD045ogni immagine ha l’alt text
MD051i link #ancora puntano a heading esistenti
MD059niente “clicca qui”, “qui”, “link”, “altro” come testo di un link
MD024niente heading duplicati (romperebbero le ancore)
MD044capitalizzazione coerente dei nomi propri (JavaScript, Obsidian, Astro)
MD043struttura 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 Obsidian

Verificato: 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 GFM

Per digerire un po’ di sintassi Obsidian:

pandoc -f markdown+mark+wikilinks_title_after_pipe+tex_math_dollars nota.md -o nota.html

mark 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

  1. Tabella senza riga di separazione → resta testo. Serve | --- | --- |.
  2. Sottolista con indentazione insufficiente → diventa una lista sorella. Allinea alla colonna del testo dell’item genitore.
  3. --- dopo un paragrafo → diventa un H2 e si mangia il paragrafo. Metti una riga vuota, o usa ***.
  4. a*b*c diventa corsivo → usa i backtick o escapa.
  5. A capo che spariscono → un invio singolo è uno spazio. Usa \ a fine riga.
  6. Hard break cancellato dall’editor → i due spazi finali sono invisibili e fragili.
  7. Lista che “si allarga” → una riga vuota di troppo l’ha resa loose.
  8. “ pubblicato → fuori da Obsidian è testo normale.
  9. Cella di tabella troncata → una pipe non escapata, anche dentro il codice.
  10. Link #ancora rotto → 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]  ![alt](img.png)
<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 nota

7.8 Dove continuare

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.