# Le due approcci di riscrittura BBCode di Discourse dovrebbero condividere un'API centrale?

**URL:** <https://meta.discourse.org/t/should-discourses-two-bbcode-rewriting-approaches-share-a-core-api/415964>\
**Category:** Development\
**Tags:** events\
**Created:** [28 Ottobre 2026, 7:50am UTC](https://meta.discourse.org/t/should-discourses-two-bbcode-rewriting-approaches-share-a-core-api/415964 "2026-10-28T07:50:45Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)\
**Post date:** [28 Ottobre 2026, 7:50am UTC](https://meta.discourse.org/t/should-discourses-two-bbcode-rewriting-approaches-share-a-core-api/415964/1 "2026-10-28T07:50:45Z")

</div>

Due PR aperte introducono approcci diversi alla modifica degli attributi BBCode nel testo grezzo dei post:

- [#43187 — Aggiunta della modalità topic successore per eventi ricorrenti](https://github.com/discourse/discourse/pull/43187) introduce `BbcodeRewriter`, che identifica un Evento renderizzato e riscrive in modo sicuro il tag di apertura BBCode corrispondente durante il rollover automatico.

- [#42932 — Aggiunta delle azioni Evento ai workflow](https://github.com/discourse/discourse/pull/42932) introduce `PrettyText.update_bbcode_attributes`, che localizza un blocco BBCode analizzato e ne aggiorna gli attributi quando un workflow apre o chiude un Evento.

Durante la revisione di #43187, [Martin ha suggerito di estrarre la funzionalità generica di manipolazione BBCode](https://github.com/discourse/discourse/pull/43187#discussion_r4374067035) dal servizio specifico per gli Eventi.

Inizialmente ho incluso alcune funzionalità basate su token dalla altra PR, ma questo ha introdotto due meccanismi di riscrittura all’interno di [#43187](https://github.com/discourse/discourse/pull/43187). Poiché l’API basata su token non aveva alcun chiamante in produzione in quel branch, l’ho [rimossa nel commit 6d13371](https://github.com/discourse/discourse/pull/43187/commits/6d13371aae5).

L’API basata su token rimane comunque utile indipendentemente per [#42932](https://github.com/discourse/discourse/pull/42932).

Mi sono chiesto se questi due approcci dovessero eventualmente convergere in un’unica API core riutilizzabile, oppure se i loro requisiti diversi giustifichino il mantenimento di entrambi.

## Confronto delle implementazioni attuali

La tabella descrive ciò che il codice implementa attualmente, senza suggerire che uno dei due approcci sia intrinsecamente errato.

| Capacità | `BbcodeRewriter` ([#43187](https://github.com/discourse/discourse/pull/43187)) | API basata su token ([#42932](https://github.com/discourse/discourse/pull/42932)) | Significato e importanza |
| --- | --- | --- | --- |
| **1. Utilizzo del parser BBCode di Discourse** | Scansiona i tag di apertura candidati utilizzando `parseBBCodeTag`, la stessa grammatica di tag di apertura usata dal motore Markdown. | Usa `DiscourseMarkdownIt.parse` per ottenere i token Markdown e trovare un blocco BBCode corrispondente. | **Entrambi gli approcci comprendono la sintassi BBCode** , anziché affidarsi esclusivamente a una regex indipendente. Differiscono nel modo in cui identificano il tag da modificare. |
| **2. Selezione del blocco BBCode target** | Segna temporaneamente i tag di apertura candidati, renderizza il post e identifica il candidato corrispondente a un elemento HTML selezionato, come `div.discourse-post-event`. | Seleziona il primo token BBCode analizzato il cui `meta.bbcode` corrisponde al nome del tag richiesto. | **L’identità dell’obiettivo è importante.** #43187 deve associare il BBCode grezzo all’Evento effettivamente renderizzato da Discourse. Il workflow di #42932 usa il primo blocco Evento analizzato corrispondente. |
| **3. Gestione di target mancanti o ambigui** | Solleva `TargetNotFound`, `AmbiguousTarget` o `UnsupportedRenderer` quando un target non può essere identificato in modo affidabile. | Restituisce `null` se non esiste un blocco analizzato corrispondente; altrimenti seleziona la prima corrispondenza. | **Il comportamento in caso di errore differisce.** #43187 rifiuta deliberatamente modifiche automatiche ambigue. La selezione del primo blocco analizzato potrebbe essere sufficiente quando il chiamante si aspetta un solo blocco rilevante. |
| **4. Verifica della mappatura grezzo-renderizzato** | Renderizza il contenuto contrassegnato, controlla il marker sull’elemento HTML previsto e conferma che l’inserimento e la rimozione del marker lascino invariato l’HTML renderizzato. | Utilizza i metadati dei token del parser Markdown per localizzare il tag di apertura senza un ulteriore controllo di identità dell’HTML renderizzato. | **Questo protegge dalla modifica del target renderizzato sbagliato.** È particolarmente rilevante quando un job in background archivia automaticamente un Evento esistente, ma comporta rendering aggiuntivi e complessità. |
| **5. Controllo del tag di apertura selezionato** | Prima della riscrittura, riconsidera il grezzo fornito e verifica che il candidato selezionato corrisponda ancora al testo del tag di apertura atteso. | Localizza il tag di apertura corrispondente durante la chiamata di aggiornamento senza un confronto separato con il tag di apertura atteso. | **Questo è un controllo di coerenza interna.** Aiuta ad evitare di riscrivere un candidato che non corrisponde più alla selezione precedente. Da solo, non è una protezione contro modifiche concorrenti al database. |
| **6. Gestione dei nomi degli attributi e dei valori esistenti** | Riscrive gli attributi selezionati utilizzando i confini degli attributi del parser. Normalizza anche i nomi degli attributi renderizzati equivalenti, permettendo a varianti come `Recurrence` e `recurrence` di essere rimosse in modo coerente. | Usa le corrispondenze dei token degli attributi per sostituire o rimuovere i nomi richiesti e il serializer condiviso degli attributi BBCode per inserire i valori. | **Entrambi mirano a preservare gli attributi non correlati.** La normalizzazione dei nomi equivalenti è particolarmente importante quando si archivia un Evento, poiché lasciare alle spalle un alias di ricorrenza potrebbe causare che l’Evento completato rimanga ricorrente. |
| **7. Validazione del tag riscritto** | Analizza nuovamente il tag di apertura riscritto e verifica che i suoi attributi corrispondano ai valori previsti. Un round-trip non valido solleva un errore. | Produce direttamente il tag di apertura riscritto, senza un equivalente passo finale di analisi e confronto. | **La validazione del round-trip cattura problemi di serializzazione** , come valori di attributi modificati o confini malformati. L’approccio basato su token è più semplice ma si affida alla sua logica di riscrittura e ai test piuttosto che a questo controllo runtime aggiuntivo. |
| **8. Preservazione del contenuto del post non correlato** | Modifica il tag di apertura selezionato mantenendo il contenuto grezzo circostante. Controlla anche che i valori degli attributi non correlati sopravvivano alla riscrittura. | Sostituisce la sottostringa del tag di apertura selezionato mantenendo il contenuto grezzo circostante e gli attributi non richiesti per la modifica. | **Entrambi devono evitare modifiche indesiderate al post.** Una modifica relativa a un Evento non dovrebbe modificare silenziosamente la discussione circostante o attributi BBCode non correlati. |
| **9. Costo di implementazione** | Richiede scansione dei candidati, marker temporanei, rendering del post, ispezione dell’HTML, riscrittura degli attributi e validazione. | Analizza i token Markdown, seleziona il primo tag di apertura corrispondente e lo riscrive direttamente. | **Controlli runtime più forti hanno un costo.** La domanda è se le misure di sicurezza extra dovrebbero essere disponibili a tutti i chiamanti, opzionali, o implementate solo dove l’applicazione le richiede. |

## Perché i requisiti differiscono

Per [#43187](https://github.com/discourse/discourse/pull/43187), il rollover del successore viene eseguito automaticamente quando un’occorrenza termina. L’Evento originale viene archiviato come occorrenza non ricorrente e viene creato un nuovo Topic per l’occorrenza successiva.

Se viene modificato il blocco `[event]` sbagliato, o se gli attributi riscritti non rappresentano più l’Evento previsto, l’errore potrebbe persistere attraverso i tentativi di rollover automatico.

Per [#42932](https://github.com/discourse/discourse/pull/42932), l’azione del workflow richiede esplicitamente che un Evento venga aperto o chiuso. La sua attuale implementazione basata su token modifica il primo blocco Evento analizzato corrispondente.

L’approccio basato su token non è quindi necessariamente inadatto per quel caso d’uso. Fornisce semplicemente garanzie diverse di selezione e validazione.

Entrambi gli approcci condividono già alcune infrastrutture sottostanti, tra cui `parseBBCodeTag` e `serializeBBCodeAttr`.

## Possibile direzione per un’astrazione condivisa

Una possibilità potrebbe essere quella di separare tre responsabilità:

1. **Trovare un tag di apertura BBCode** — usando token del parser, selezione esplicita dei candidati o mappatura di elementi renderizzati.

2. **Riscrivere i suoi attributi** — usando un’unica implementazione condivisa per i confini degli attributi, la serializzazione e la preservazione dei valori non correlati.

3. **Validare il risultato** — applicando facoltativamente l’identità del target, il rilevamento dell’ambiguità, l’equivalenza del contenuto renderizzato o i controlli di round-trip degli attributi, a seconda del chiamante.

Ciò potrebbe consentire ai workflow più semplici di utilizzare una selezione di token diretta, mentre le operazioni di modifica automatica più sensibili richiedono misure di sicurezza più forti.

Tuttavia, potrebbe anche introdurre una complessità inutile rispetto al mantenimento di due API più piccole.

## Domanda per i maintainer

Sarebbe preferibile che le due PR mantengano le loro API di riscrittura separate, dato i loro diversi requisiti di selezione del target?

In alternativa, un riscrittore di attributi a basso livello condiviso con selezione del target e validazione configurabili sarebbe una direzione migliore a lungo termine?

Sono particolarmente interessato a sapere se i controlli di sicurezza aggiuntivi attualmente implementati da `BbcodeRewriter` siano considerati funzionalità core generalmente utili, oppure se debbano rimanere specifici per casi d’uso che necessitano di garanzie più forti.

Non sto proponendo che una delle due PR debba bloccare l’altra; l’obiettivo è evitare duplicazioni non necessarie nell’infrastruttura BBCode core di Discourse man mano che entrambe le funzionalità si sviluppano.
