fix(renderer): ordered list items always showed 1. — emit value= on each li (#886) (#904)

* fix(renderer): ordered list items always showed 1. — emit value= on each <li> (#886)

Root cause: when LLMs output numbered lists with blank lines between items,
renderMd()'s paragraph-splitter (split(/\n{2,}/)) breaks the markdown into
one chunk per item. The ordered-list regex then wraps each item in its own
<ol>, and since each <ol> restarts at 1, the rendered output is always 1. 1. 1.

Fix: capture the original number from each list line and emit value="N" on
every <li>. The HTML spec guarantees that value= overrides the <ol> counter,
so even items in separate <ol> containers display their correct ordinal.

6 regression tests in tests/test_886_ordered_list_numbering.py.
1958 tests pass.

* chore: add v0.50.173 CHANGELOG entry for ordered list fix

---------

Co-authored-by: Hermes Bedrock Fix <hermes-fixes@local>
Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
This commit is contained in:
nesquena-hermes
2026-04-23 12:15:56 -07:00
committed by GitHub
parent 9dd6e3f338
commit 537c8271db
3 changed files with 110 additions and 1 deletions

View File

@@ -642,12 +642,19 @@ function renderMd(raw){
}
return html+'</ul>';
});
// Ordered lists: use value= on each <li> so the correct number is preserved
// even when blank lines between items cause the paragraph splitter to place
// each item in its own <ol> container — without value= every <ol> restarts
// at 1, producing "1. 1. 1." instead of "1. 2. 3." (#886).
s=s.replace(/((?:^(?: )?\d+\. .+\n?)+)/gm,block=>{
const lines=block.trimEnd().split('\n');
let html='<ol>';
for(const l of lines){
const numMatch=l.match(/^\s*(\d+)\. /);
const num=numMatch?parseInt(numMatch[1],10):null;
const text=l.replace(/^ {0,4}\d+\. /,'');
html+=`<li>${inlineMd(text)}</li>`;
const valAttr=num!==null?` value="${num}"`:'';
html+=`<li${valAttr}>${inlineMd(text)}</li>`;
}
return html+'</ol>';
});