= 2) { break; } // Past a long run of empty ones, it's just taken not to end in a blank line if (++$siblings > 100) { return ' '; } } return (string) \substr($markdown, -2); } /** * Whether anything other than whitespace has been output for the nearest earlier siblings of the given element */ public static function hasContent(ElementInterface $element): bool { $siblings = 0; foreach (self::getSiblingValues($element) as $value) { if (\trim($value) !== '') { return true; } if (++$siblings > 100) { break; } } return false; } /** * Whether a code span output next would have its delimiter merged with a backtick, or escaped by a backslash */ public static function endsInDelimiterHazard(ElementInterface $element): bool { // Only a whole run of backslashes says whether the last one is itself escaped $backslashes = 0; for ($node = $element; $node !== null; $node = $node->getParent()) { foreach (self::getSiblingValues($node) as $value) { $trimmed = \rtrim($value, '\\'); $backslashes += \strlen($value) - \strlen($trimmed); if ($trimmed !== '') { return $backslashes % 2 === 1 || ($backslashes === 0 && \substr($trimmed, -1) === '`'); } } } return $backslashes % 2 === 1; } /** * @return iterable The Markdown of each earlier sibling, nearest first */ private static function getSiblingValues(ElementInterface $element): iterable { if ($element instanceof Element) { return $element->getPrecedingSiblingValues(); } $parent = $element->getParent(); if ($parent === null) { return []; } // Without access to the node itself, it can only be assumed to be the first child not yet converted to text $values = []; foreach ($parent->getChildren() as $sibling) { if (! $sibling->isText()) { break; } $values[] = $sibling->getValue(); } return \array_reverse($values); } }