fix(whatsapp): Preserve ordered list numbering in messages (#13339)

- Fix ordered lists being sent as unordered lists in WhatsApp
integrations
- The WhatsApp markdown renderer was converting all lists to bullet
points (-), ignoring numbered list formatting
- Added ordered list support by tracking list_type and list_item_number
from CommonMarker AST metadata

Before:
Input: "1. First\n2. Second\n3. Third"
Output: "- First\n- Second\n- Third"

After:

Input: "1. First\n2. Second\n3. Third"
Output: "1. First\n2. Second\n3. Third"
This commit is contained in:
Pranav
2026-01-22 02:14:40 -08:00
committed by GitHub
parent 70d09fcc66
commit 9e97cc0cdd
2 changed files with 57 additions and 11 deletions

View File

@@ -1,4 +1,9 @@
class Messages::MarkdownRenderers::WhatsAppRenderer < Messages::MarkdownRenderers::BaseMarkdownRenderer class Messages::MarkdownRenderers::WhatsAppRenderer < Messages::MarkdownRenderers::BaseMarkdownRenderer
def initialize
super
@list_item_number = 0
end
def strong(_node) def strong(_node)
out('*', :children, '*') out('*', :children, '*')
end end
@@ -15,13 +20,20 @@ class Messages::MarkdownRenderers::WhatsAppRenderer < Messages::MarkdownRenderer
out(node.url) out(node.url)
end end
def list(_node) def list(node)
@list_type = node.list_type
@list_item_number = @list_type == :ordered_list ? node.list_start : 0
out(:children) out(:children)
cr cr
end end
def list_item(_node) def list_item(_node)
out('- ', :children) if @list_type == :ordered_list
out("#{@list_item_number}. ", :children)
@list_item_number += 1
else
out('- ', :children)
end
cr cr
end end

View File

@@ -53,12 +53,28 @@ RSpec.describe Messages::MarkdownRendererService, type: :service do
expect(result.strip).to eq('*bold _italic_*') expect(result.strip).to eq('*bold _italic_*')
end end
it 'converts bullet lists' do it 'preserves unordered list with dash markers' do
content = "- item 1\n- item 2" content = "- item 1\n- item 2\n- item 3"
result = described_class.new(content, channel_type).render result = described_class.new(content, channel_type).render
expect(result.strip).to include('- item 1') expect(result).to include('- item 1')
expect(result.strip).to include('- item 2') expect(result).to include('- item 2')
expect(result).to include("- item 1\n- item 2") expect(result).to include('- item 3')
end
it 'converts asterisk unordered lists to dash markers' do
content = "* item 1\n* item 2\n* item 3"
result = described_class.new(content, channel_type).render
expect(result).to include('- item 1')
expect(result).to include('- item 2')
expect(result).to include('- item 3')
end
it 'preserves ordered list markers with numbering' do
content = "1. first step\n2. second step\n3. third step"
result = described_class.new(content, channel_type).render
expect(result).to include('1. first step')
expect(result).to include('2. second step')
expect(result).to include('3. third step')
end end
it 'preserves newlines in plain text without list markers' do it 'preserves newlines in plain text without list markers' do
@@ -432,6 +448,24 @@ RSpec.describe Messages::MarkdownRendererService, type: :service do
expect(result).to include("Line 1\nLine 2\nLine 3") expect(result).to include("Line 1\nLine 2\nLine 3")
end end
it 'preserves ordered list markers with numbering in Twilio WhatsApp' do
content = "1. first step\n2. second step\n3. third step"
channel = instance_double(Channel::TwilioSms, whatsapp?: true)
result = described_class.new(content, channel_type, channel).render
expect(result).to include('1. first step')
expect(result).to include('2. second step')
expect(result).to include('3. third step')
end
it 'preserves unordered list markers in Twilio WhatsApp' do
content = "- item 1\n- item 2\n- item 3"
channel = instance_double(Channel::TwilioSms, whatsapp?: true)
result = described_class.new(content, channel_type, channel).render
expect(result).to include('- item 1')
expect(result).to include('- item 2')
expect(result).to include('- item 3')
end
it 'backwards compatible when channel is not provided' do it 'backwards compatible when channel is not provided' do
content = '**bold** _italic_' content = '**bold** _italic_'
result = described_class.new(content, channel_type).render result = described_class.new(content, channel_type).render
@@ -483,12 +517,12 @@ RSpec.describe Messages::MarkdownRendererService, type: :service do
context 'when testing all formatting types' do context 'when testing all formatting types' do
let(:channel_type) { 'Channel::Whatsapp' } let(:channel_type) { 'Channel::Whatsapp' }
it 'handles ordered lists' do it 'handles ordered lists with proper numbering' do
content = "1. first\n2. second\n3. third" content = "1. first\n2. second\n3. third"
result = described_class.new(content, channel_type).render result = described_class.new(content, channel_type).render
expect(result).to include('first') expect(result).to include('1. first')
expect(result).to include('second') expect(result).to include('2. second')
expect(result).to include('third') expect(result).to include('3. third')
end end
end end