Discourse의 두 가지 BBCode 재작성 방식이 핵심 API를 공유해야 하나요?

두 개의 열린 PR(풀 리퀘스트)은 게시글 원본(raw)에서 BBCode 속성을 편집하는 서로 다른 접근법을 도입합니다:

#43187 리뷰 중 Martin은 이벤트 전용 서비스에서 범용 BBCode 조작 기능을 추출할 것을 제안했습니다.

저는 처음에 다른 PR의 관련 토큰 기반 기능 일부를 포함시켰지만, 이로 인해 #43187 내에 두 가지 재작성 메커니즘이 도입되었습니다. 해당 브랜치에서 토큰 기반 API에는 프로덕션 호출자가 없었으므로, 저는 commit 6d13371에서 이를 제거했습니다.

토큰 기반 API는 여전히 #42932에 대해 독립적으로 유용합니다.

저는 이 두 가지 접근법이 궁극적으로 하나의 재사용 가능한 핵심 API로 수렴해야 하는지, 아니면 서로 다른 요구 사항 때문에 둘 다 유지하는 것이 정당화되는지 궁금했습니다.

현재 구현 비교

아래 표는 어느 쪽 접근법이 본질적으로 잘못되었다고 제안하기보다는 코드가 현재 구현하는 내용을 설명합니다.

기능 BbcodeRewriter (#43187) 토큰 기반 API (#42932) 의미 및 중요성
1. Discourse의 BBCode 파서 사용 Markdown 엔진에서 사용하는 것과 동일한 시작 태그 문법을 가진 parseBBCodeTag를 사용하여 후보 시작 태그를 스캔합니다. Markdown 토큰을 얻어 일치하는 BBCode 블록을 찾기 위해 DiscourseMarkdownIt.parse를 사용합니다. 두 접근법 모두 BBCode 구문을 이해하며, 독립적인 정규 표현식에만 의존하지 않습니다. 편집할 태그를 식별하는 방식에서 차이가 있습니다.
2. 대상 BBCode 블록 선택 후보 시작 태그를 일시적으로 표시(mark)하고 게시글을 렌더링한 뒤, div.discourse-post-event와 같은 선택된 HTML 요소에 해당하는 후보를 식별합니다. 요청된 태그 이름과 meta.bbcode가 일치하는 첫 번째 파싱된 BBCode 토큰을 선택합니다. 대상 동일성이 중요합니다. #43187은 Discourse가 실제로 렌더링한 이벤트와 원본 BBCode를 연관시켜야 합니다. #42932의 워크플로는 첫 번째 일치하는 파싱된 이벤트 블록을 사용합니다.
3. 누락되거나 모호한 대상 처리 대상을 신뢰할 수 있게 식별할 수 없을 때 TargetNotFound, AmbiguousTarget 또는 UnsupportedRenderer를 발생시킵니다. 일치하는 파싱된 블록이 없으면 null을 반환하고, 그렇지 않으면 첫 번째 일치 항목을 선택합니다. 실패 동작이 다릅니다. #43187은 모호한 자동 편집을 의도적으로 거부합니다. 호출자가 관련 블록이 하나만 있을 것으로 기대하는 경우, 첫 번째 파싱된 블록을 선택하는 것으로 충분할 수 있습니다.
4. 원본-렌더링 매핑 검증 표시된 콘텐츠를 렌더링하고 의도된 HTML 요소에 마커가 있는지 확인하며, 마커 삽입 및 삭제가 렌더링된 HTML을 변경하지 않는지 확인합니다. 추가적인 렌더링된 HTML 동일성 검사 없이 Markdown 파서의 토큰 메타데이터를 사용하여 시작 태그를 찾습니다. 이는 잘못된 렌더링된 대상을 편집하는 것을 방지합니다. 백그라운드 잡이 기존 이벤트를 자동으로 아카이브할 때 특히 관련이 있지만, 추가적인 렌더링과 복잡성을 수반합니다.
5. 선택된 시작 태그 확인 재작성 전에 제공된 원본(raw)을 다시 스캔하여 선택된 후보가 여전히 예상되는 시작 태그 텍스트와 일치하는지 확인합니다. 별도의 예상 시작 태그 비교 없이 업데이트 호출 중에 일치하는 시작 태그를 찾습니다. 이는 내부적 일관성 검사입니다. 이전 선택과 더 이상 일치하지 않는 후보를 재작성하는 것을 방지하는 데 도움이 됩니다. 자체적으로는 동시 데이터베이스 편집에 대한 보호 장치가 아닙니다.
6. 속성 이름 및 기존 값 처리 파서의 속성 경계를 사용하여 선택된 속성을 재작성합니다. 또한 등가 렌더링 속성 이름을 정규화하여 Recurrence와 recurrence와 같은 변형이 일관되게 제거될 수 있도록 허용합니다. 속성 토큰 매칭을 사용하여 요청된 이름을 대체하거나 제거하고, 공유 BBCode 속직 직렬화기를 사용하여 값을 삽입합니다. 둘 다 무관한 속성을 보존하려는 목적을 가집니다. 이벤트 아카이빙 시 등가 이름 정규화는 특히 중요합니다. 재귀(recurrence) 별명을 남겨두면 완료된 이벤트가 여전히 반복적으로 남을 수 있기 때문입니다.
7. 재작성된 태그 검증 재작성된 시작 태그를 다시 파싱하여 그 속성이 의도된 값과 일치하는지 확인합니다. 잘못된 왕복(round-trip)은 오류를 발생시킵니다. 최종 파싱 및 비교 단계 없이 재작성된 시작 태그를 직접 생성합니다. 왕복 검증을 통해 직렬화 문제를 포착합니다. 예를 들어 변경된 속성 값이나 잘못된 경계 등입니다. 토큰 기반 접근법은 더 단순하지만 이 추가 런타임 검사 대신 재작성 로직과 테스트에 의존합니다.
8. 무관한 게시글 콘텐츠 보존 주변 원본 콘텐츠를 유지하면서 선택된 시작 태그만 변경합니다. 또한 무관한 속성 값이 재작성을 견디는지 확인합니다. 주변 원본 콘텐츠와 수정을 요청받지 않은 속성을 유지하면서 선택된 시작 태그 부분 문자열만 대체합니다. 둘 다 의도하지 않은 게시글 변경을 피해야 합니다. 이벤트 관련 편집은 주변 토론이나 무관한 BBCode 속성을 조용히 변경해서는 안 됩니다.
9. 구현 비용 후보 스캔, 일시적 마커, 게시글 렌더링, HTML 검사, 속성 재작성 및 검증을 필요로 합니다. Markdown 토큰을 파싱하고 첫 번째 일치하는 시작 태그를 선택하여 직접 재작성합니다. 더 강력한 런타임 검사는 비용을 수반합니다. 추가적인 안전장치를 모든 호출자에게 제공해야 하는지, 선택적이어야 하는지, 아니면 애플리케이션이 필요로 하는 곳에만 구현해야 하는지가 문제입니다.

왜 요구 사항이 다른가

#43187의 경우, 후속 롤오버는 한 occurrence(발생)가 끝나면 자동으로 실행됩니다. 원래 이벤트는 비재귀 occurrence으로 아카이브되고, 다음 occurrence을 위한 새 토픽이 생성됩니다.

잘못된 [event] 블록이 수정되거나 재작성된 속성이 의도된 이벤트를 더 이상 대표하지 않을 경우, 오류는 자동 롤오버 시도 사이에 지속될 수 있습니다.

#42932의 경우, 워크플로 작업은 명시적으로 이벤트가 열리거나 닫히도록 요청합니다. 그 현재 토큰 기반 구현은 첫 번째 일치하는 파싱된 이벤트 블록을 수정합니다.

따라서 토큰 기반 접근법은 해당 사용 사례에 부적합하다고 단정할 수는 없습니다. 단순히 다른 선택 및 검증 보장을 제공할 뿐입니다.

두 접근법은 이미 parseBBCodeTag와 serializeBBCodeAttr를 포함한 일부 기본 인프라를 공유합니다.

공유 추상화를 위한 가능한 방향

하나의 가능성은 세 가지 책임을 분리하는 것입니다:

  1. BBCode 시작 태그 찾기 — 파서 토큰, 명시적 후보 선택 또는 렌더링된 요소 매핑을 사용하여.

  2. 그 속성 재작성 — 속성 경계, 직렬화 및 무관한 값 보존을 위한 하나의 공유 구현을 사용하여.

  3. 결과 검증 — 호출자에 따라 대상 동일성 강제, 모호성 감지, 렌더링된 콘텐츠 동등성 또는 속성 왕복 검사를 선택적으로 적용.

이를 통해 더 단순한 워크플로가 직관적인 토큰 선택을 사용할 수 있고, 더 민감한 자동 편집 작업은 더 강력한 안전장치를 요청할 수 있게 될 것입니다.

그러나 이는 두 개의 더 작은 API를 유지하는 것보다 불필요한 복잡성을 도입할 수도 있습니다.

유지보수자를 위한 질문

서로 다른 대상 선택 요구 사항을 고려할 때, 두 PR이 각자의 별도 재작성 API를 유지하는 것이 바람직할까요?

또는 구성 가능한 대상 선택 및 검증을 가진 공유 저 수준 속성 재작성기가 장기적으로 더 나은 방향일까요?

특히 BbcodeRewriter가 현재 구현하는 추가적인 안전 검사가 일반적으로 유용한 핵심 기능으로 간주되어야 하는지, 아니면 더 강한 보장이 필요한 사용 사례에 특정되어 남아야 하는지에 대해 관심이 많습니다.

저는 어느 쪽 PR이 다른 쪽을 블로킹해야 한다고 제안하는 것이 아닙니다. 목표는 두 기능이 발전함에 따라 Discourse의 핵심 BBCode 인프라에서 불필요한 중복을 피하는 것입니다.

1개의 좋아요