Files
thephpleague-html-to-markdown/PR.md
T
dualfroz 19b1be8421 fix: honor start="0" on ordered lists
The ordered-list numbering used intval() on the "start" attribute inside a
truthiness check, so a valid start="0" was treated as absent and the list
restarted numbering at 1. Detect an explicit numeric start attribute with
is_numeric() instead, so <ol start=\"0\"> renders as 0. 1. ...
2026-09-04 09:09:23 +02:00

2.3 KiB

fix: honor start="0" on ordered lists

Problem

Converting an ordered list whose start attribute is 0 produces the wrong numbering: the list restarts at 1 instead of 0.

$converter = new League\HTMLToMarkdown\HtmlConverter();
$converter->convert('<ol start="0"><li>Item A</li><li>Item B</li></ol>');
// actual:   "1. Item A\n2. Item B"
// expected: "0. Item A\n1. Item B"

<ol start="0"> is valid HTML, and CommonMark supports ordered lists that begin at 0, so the resulting Markdown is incorrect. Any other start value (for example start="120") works.

Root cause

src/Converter/ListItemConverter.php:55. The start value was read inside a truthiness check:

if ($listType === 'ol' && ($parent = $element->getParent()) && ($start = \intval($parent->getAttribute('start')))) {
    $number = $start + $element->getSiblingPosition() - 1;
} else {
    $number = $element->getSiblingPosition();
}

\intval('0') is 0, which is falsy, so an explicit start="0" takes the else branch and the list is renumbered from the sibling position (1-based). The check cannot distinguish "start attribute absent" from "start attribute set to 0", because getAttribute('start') returns '' when the attribute is missing and intval('') is also 0.

The fix

Detect an explicitly provided numeric start attribute with \is_numeric() instead of relying on the truthiness of intval():

if ($listType === 'ol' && ($parent = $element->getParent()) && \is_numeric($start = $parent->getAttribute('start'))) {
    $number = (int) $start + $element->getSiblingPosition() - 1;
} else {
    $number = $element->getSiblingPosition();
}

\is_numeric('') is false (missing attribute -> normal numbering) while \is_numeric('0') is true, so start="0" is now respected. Existing values such as start="120" are unaffected.

Test

Added an assertion in HtmlConverterTest::testLists:

$this->assertHtmlGivesMarkdown('<ol start="0"><li>Item A</li><li>Item B</li></ol>', "0. Item A\n1. Item B");

Gate

composer install && vendor/bin/phpunit --no-coverage

Result: exit code 0 - OK (50 tests, 230 assertions).

Counterfactual: reverting ListItemConverter to the intval() truthiness check fails the new assertion - <ol start="0"> yields 1. Item A\n2. Item B instead of 0. Item A\n1. Item B.