diff --git a/confluence-mdx/bin/reverse_sync/xhtml_patcher.py b/confluence-mdx/bin/reverse_sync/xhtml_patcher.py index 8d7fdac6a..bedb1e00d 100644 --- a/confluence-mdx/bin/reverse_sync/xhtml_patcher.py +++ b/confluence-mdx/bin/reverse_sync/xhtml_patcher.py @@ -290,9 +290,22 @@ def _apply_text_changes(element: Tag, old_text: str, new_text: str): ) node_str = str(node) - # 원본 whitespace 보존 + # 원본 whitespace 보존 (단, diff에서 삭제된 선행 공백은 제거) leading = node_str[:len(node_str) - len(node_str.lstrip())] trailing = node_str[len(node_str.rstrip()):] + + # 직전 노드 범위와 현재 노드 범위 사이의 gap이 diff로 삭제된 경우, + # leading whitespace를 제거한다. + # 예: IDENTIFIER 조사 → IDENTIFIER조사 (공백 교정) + if leading and i > 0: + prev_end = node_ranges[i - 1][1] + if prev_end < node_start: + gap_new = _map_text_range( + old_stripped, new_stripped, opcodes, prev_end, node_start + ) + if not gap_new: + leading = '' + node.replace_with(NavigableString(leading + new_node_text + trailing)) diff --git a/confluence-mdx/tests/test_reverse_sync_xhtml_patcher.py b/confluence-mdx/tests/test_reverse_sync_xhtml_patcher.py index 0b3614157..5621badf0 100644 --- a/confluence-mdx/tests/test_reverse_sync_xhtml_patcher.py +++ b/confluence-mdx/tests/test_reverse_sync_xhtml_patcher.py @@ -237,3 +237,27 @@ def test_legacy_patch_without_action_treated_as_modify(self): 'new_plain_text': 'New text'}] result = patch_xhtml(xhtml, patches) assert 'New text' in result + + +def test_remove_space_before_korean_particle_after_strong(): + """ 뒤 조사 앞 공백 제거를 올바르게 패치한다. + + XHTML:

... AGENT_SECRET 를 변경해도 괜찮은가요?

+ 교정: 'AGENT_SECRET 를' → 'AGENT_SECRET를' (공백 제거) + + old_plain_text는 xhtml_plain_text(element.get_text())에서 오므로 double-space를 포함. + 다음 text node의 leading whitespace가 diff에서 삭제된 경우, + xhtml_patcher가 해당 공백도 제거해야 한다. + """ + xhtml = '

Q: 운영 도중 AGENT_SECRET 를 변경해도 괜찮은가요?

' + patches = [ + { + 'xhtml_xpath': 'h3[1]', + # old_plain_text는 element.get_text()에서 오므로 XHTML 그대로의 공백 포함 + 'old_plain_text': 'Q: 운영 도중 AGENT_SECRET 를 변경해도 괜찮은가요?', + 'new_plain_text': 'Q: 운영 도중 AGENT_SECRET를 변경해도 괜찮은가요?', + } + ] + result = patch_xhtml(xhtml, patches) + assert 'AGENT_SECRET를 변경해도' in result + assert 'AGENT_SECRET 를 변경해도' not in result