¿Deben compartir las dos aproximaciones de reescritura BBCode de Discourse una API central?

Dos PR abiertos introducen enfoques diferentes para editar atributos BBCode en el texto original de una publicación:

Durante la revisión de #43187, Martin sugirió extraer la funcionalidad genérica de manipulación de BBCode del servicio específico de Eventos.

Inicialmente incluí algunas funciones basadas en tokens relacionadas del otro PR, pero esto introdujo dos mecanismos de reescritura dentro de #43187. Dado que la API basada en tokens no tenía ningún llamador en producción en esa rama, la eliminó en el commit 6d13371.

La API basada en tokens sigue siendo útil de forma independiente para #42932.

Me pregunté si estos dos enfoques deberían converger eventualmente en una única API central reutilizable, o si sus requisitos diferentes justifican mantener ambos.

Comparación de las implementaciones actuales

La tabla describe lo que el código implementa actualmente, sin sugerir que ninguno de los enfoques sea inherentemente incorrecto.

Capacidad BbcodeRewriter (#43187) API basada en tokens (#42932) Significado e importancia
1. Utiliza el parser BBCode de Discourse Escanea etiquetas de apertura candidatas usando parseBBCodeTag, la misma gramática de etiquetas de apertura utilizada por el motor Markdown. Usa DiscourseMarkdownIt.parse para obtener tokens de Markdown y encontrar un bloque BBCode coincidente. Ambos enfoques entienden la sintaxis BBCode, en lugar de depender únicamente de una expresión regular independiente. Difieren en cómo identifican la etiqueta a editar.
2. Selecciona el bloque BBCode objetivo Marca temporalmente etiquetas de apertura candidatas, renderiza la publicación e identifica el candidato correspondiente a un elemento HTML seleccionado, como div.discourse-post-event. Selecciona el primer token BBCode analizado cuyo meta.bbcode coincida con el nombre de etiqueta solicitado. La identidad del objetivo es importante. #43187 necesita asociar el BBCode original con el Evento que Discourse realmente renderizó. El flujo de trabajo de #42932 utiliza el primer bloque de Evento analizado que coincide.
3. Maneja objetivos faltantes o ambiguos Lanza TargetNotFound, AmbiguousTarget o UnsupportedRenderer cuando un objetivo no puede identificarse de manera confiable. Devuelve null si no existe un bloque analizado coincidente; de lo contrario, selecciona la primera coincidencia. El comportamiento ante el fallo difiere. #43187 se niega deliberadamente a realizar ediciones automáticas ambiguas. Seleccionar el primer bloque analizado puede ser suficiente cuando el llamador espera solo un bloque relevante.
4. Verifica el mapeo de original a renderizado Renderiza el contenido marcado, comprueba el marcador en el elemento HTML previsto y confirma que insertar y eliminar el marcador deja el HTML renderizado sin cambios. Utiliza los metadatos de tokens del parser de Markdown para localizar la etiqueta de apertura sin una verificación adicional de identidad del HTML renderizado. Esto protege contra editar el objetivo renderizado equivocado. Es particularmente relevante cuando un trabajo en segundo plano archiva automáticamente un Evento existente, pero implica renderizado adicional y complejidad.
5. Comprueba la etiqueta de apertura seleccionada Antes de reescribir, vuelve a escanear el original proporcionado y verifica que el candidato seleccionado aún coincida con el texto de etiqueta de apertura esperado. Localiza la etiqueta de apertura coincidente durante la llamada de actualización sin una comparación separada de apertura esperada. Esta es una verificación de consistencia interna. Ayuda a evitar reescribir un candidato que ya no coincide con la selección anterior. Por sí solo, no es protección contra ediciones concurrentes en la base de datos.
6. Maneja nombres de atributos y valores existentes Reescribe los atributos seleccionados utilizando los límites de atributos del parser. También normaliza nombres de atributos renderizados equivalentes, permitiendo que variantes como Recurrence y recurrence se eliminen de manera consistente. Utiliza coincidencias de tokens de atributo para reemplazar o eliminar nombres solicitados y el serializador compartido de atributos BBCode para insertar valores. Ambos buscan preservar atributos no relacionados. Normalizar nombres equivalentes es especialmente importante al archivar un Evento, porque dejar un alias de recurrencia podría causar que el Evento completado siga siendo recurrente.
7. Valida la etiqueta reescrita Vuelve a analizar la etiqueta de apertura reescrita y comprueba que sus atributos coincidan con los valores previstos. Un recorrido inválido lanza un error. Produce directamente la etiqueta de apertura reescrita, sin un paso equivalente de análisis y comparación final. La validación de ida y vuelta detecta problemas de serialización, como valores de atributo cambiados o límites malformados. El enfoque basado en tokens es más simple, pero depende de su lógica de reescritura y pruebas en lugar de esta verificación adicional en tiempo de ejecución.
8. Preserva el contenido de la publicación no relacionado Cambia la etiqueta de apertura seleccionada mientras retiene el contenido original circundante. También verifica que los valores de atributos no relacionados sobrevivan a la reescritura. Reemplaza la subcadena de la etiqueta de apertura seleccionada mientras retiene el contenido original circundante y los atributos no solicitados para modificación. Ambos deben evitar cambios no intencionados en la publicación. Una edición relacionada con un Evento no debe modificar silenciosamente la discusión circundante ni atributos BBCode no relacionados.
9. Costo de implementación Requiere escaneo de candidatos, marcadores temporales, renderizado de la publicación, inspección de HTML, reescritura de atributos y validación. Analiza tokens de Markdown, selecciona la primera etiqueta de apertura coincidente y la reescribe directamente. Las verificaciones en tiempo de ejecución más fuertes tienen un costo. La pregunta es si las salvaguardias adicionales deberían estar disponibles para todos los llamadores, ser opcionales, o implementarse solo donde la aplicación las requiera.

Por qué los requisitos difieren

Para #43187, la rotación de sucesores se ejecuta automáticamente cuando termina una ocurrencia. El Evento original se archiva como una ocurrencia no recurrente, y se crea un nuevo Tema para la siguiente ocurrencia.

Si se modifica el bloque [event] equivocado, o si los atributos reescritos ya no representan el Evento previsto, el error podría persistir entre intentos de rotación automática.

Para #42932, la acción del flujo de trabajo solicita explícitamente que un Evento sea abierto o cerrado. Su implementación actual basada en tokens modifica el primer bloque de Evento analizado que coincide.

Por lo tanto, el enfoque basado en tokens no es necesariamente inadecuado para ese caso de uso. Simplemente proporciona garantías de selección y validación diferentes.

Ambos enfoques ya comparten cierta infraestructura subyacente, incluido parseBBCodeTag y serializeBBCodeAttr.

Posible dirección para una abstracción compartida

Una posibilidad podría ser separar tres responsabilidades:

  1. Encontrar una etiqueta de apertura BBCode — utilizando tokens del parser, selección explícita de candidatos o mapeo de elementos renderizados.

  2. Reescribir sus atributos — utilizando una implementación compartida para límites de atributos, serialización y preservación de valores no relacionados.

  3. Validar el resultado — aplicando opcionalmente la identidad del objetivo, detección de ambigüedad, equivalencia de contenido renderizado o verificaciones de ida y vuelta de atributos, según el llamador.

Esto permitiría que flujos de trabajo más simples usen una selección de tokens sencilla, mientras que operaciones de edición automática más sensibles solicitan salvaguardias más fuertes.

Sin embargo, también podría introducir complejidad innecesaria en comparación con mantener dos APIs más pequeñas.

Pregunta para los mantenedores

¿Sería preferible que los dos PR mantuvieran sus APIs de reescritura separadas, dados sus diferentes requisitos de selección de objetivos?

Alternativamente, ¿un reescritor de atributos de bajo nivel compartido con selección de objetivos y validación configurables sería una mejor dirección a largo plazo?

Me interesa particularmente si las verificaciones de seguridad adicionales actualmente implementadas por BbcodeRewriter se consideran una funcionalidad central generalmente útil, o si deberían permanecer específicas para casos de uso que necesiten garantías más fuertes.

No estoy proponiendo que ninguno de los PR necesite bloquear al otro; el objetivo es evitar duplicaciones innecesarias en la infraestructura BBCode central de Discourse a medida que ambas características evolucionan.

1 me gusta